openclaw - 💡(How to fix) Fix WhatsApp delivery leaks internal tool-trace lines (🛠️/🩹) that Discord strips

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Internal tool-call narration lines like 🛠️ print lines 1-260 from memory/2026-05-27.md (agent) and 🩹 Apply Patch are reaching end users via WhatsApp. The Discord outbound adapter strips these via stripDiscordInternalTraceLines + stripDiscordInternalRuntimeScaffolding, but the WhatsApp outbound adapter has no equivalent stripper, so they pass through to recipients.

Root Cause

WhatsApp's outbound adapter (@openclaw/whatsapp/dist/outbound-adapter-CxwUJNMD.js, lines 15–27) builds the outbound config via createWhatsAppOutboundBase(...) but supplies no sanitizeText. The base (outbound-base-Bq1UYEK5.js:43) defaults to ({ text }) => normalizeText(text) — whitespace-only normalization, no trace-line stripping.

Compare with Discord (openclaw/dist/outbound-adapter-Bw8wq78A.js:359-366):

const discordOutbound = {
  deliveryMode: "direct",
  chunker: ...,
  textChunkLimit: DISCORD_TEXT_CHUNK_LIMIT,
  sanitizeText: ({ text }) => stripDiscordInternalRuntimeScaffolding(text),
  ...
};

…and reply-delivery-mSl5EGCh.js:67-83 (stripDiscordInternalTraceLines) which strips lines matching:

const DISCORD_INTERNAL_TRACE_LINE_RE = /^(?:>\s*)?(?:📊|🛠️|📖|📝|🔍|🔎|⚙️)\s*(?:Session Status|Exec|Read|Edit|Write|Patch|Search|Open|Click|Find|Screenshot|Update Plan|Tool Call|Tool Result|Function Call|Shell|Command)\s*:/i;
const DISCORD_INTERNAL_COMPACT_COMMAND_TRACE_LINE_RE = /^(?:>\s*)?🛠️\s*(?:(?:(?:elevated|pty)\b\s*(?:·|,)\s*)+)?(?:`{1,2}\s*\S|(?:run|check|fetch|pull|push|view|show|list|switch|create|merge|rebase|stage|restore|reset|stash|search|find|print|copy|move|remove|install|start|cd|git|pnpm|npm|yarn|bun|node|python|python3|bash|sh)\b)/i;
const DISCORD_INTERNAL_CHANNEL_LINE_RE = /^(?:>\s*)?(?:analysis|commentary|tool[-_ ]?call|tool[-_ ]?result|function[-_ ]?call|thinking|reasoning)\s*[:=]/i;

These constants are named DISCORD_* and live inside extensions/discord/... even though the content they filter is not Discord-specific — it's a generic openclaw tool-display artifact that every channel should hide.

Fix Action

Fix / Workaround

Internal tool-call narration lines like 🛠️ print lines 1-260 from memory/2026-05-27.md (agent) and 🩹 Apply Patch are reaching end users via WhatsApp. The Discord outbound adapter strips these via stripDiscordInternalTraceLines + stripDiscordInternalRuntimeScaffolding, but the WhatsApp outbound adapter has no equivalent stripper, so they pass through to recipients.

🛠️ print lines 1-260 from memory/2026-05-27.md (agent)
🛠️ run test memory/2026-05-26.md → print lines 1-220 from memory/2026-05-26.md → run true (agent)
🛠️ print lines 1-260 from BOOTSTRAP.md (agent)
🩹 Apply Patch

The format matches what dist/tool-display-common-D5L_bf7a.js produces:

  • summarizeExecCommandprint lines 1-260 from <path>, joining staged pipelines with
  • classifyWorkspacePath / formatCwdSuffix → trailing (agent) for paths under .openclaw/workspace/
  • 🩹 Apply Patch from the apply_patch entry in the tool-display config

Code Example

🛠️ print lines 1-260 from memory/2026-05-27.md (agent)
🛠️ run test memory/2026-05-26.md → print lines 1-220 from memory/2026-05-26.md → run true (agent)
🛠️ print lines 1-260 from BOOTSTRAP.md (agent)
🩹 Apply Patch

---

const discordOutbound = {
  deliveryMode: "direct",
  chunker: ...,
  textChunkLimit: DISCORD_TEXT_CHUNK_LIMIT,
  sanitizeText: ({ text }) => stripDiscordInternalRuntimeScaffolding(text),
  ...
};

---

const DISCORD_INTERNAL_TRACE_LINE_RE = /^(?:>\s*)?(?:📊|🛠️|📖|📝|🔍|🔎|⚙️)\s*(?:Session Status|Exec|Read|Edit|Write|Patch|Search|Open|Click|Find|Screenshot|Update Plan|Tool Call|Tool Result|Function Call|Shell|Command)\s*:/i;
const DISCORD_INTERNAL_COMPACT_COMMAND_TRACE_LINE_RE = /^(?:>\s*)?🛠️\s*(?:(?:(?:elevated|pty)\b\s*(?:·|,)\s*)+)?(?:`{1,2}\s*\S|(?:run|check|fetch|pull|push|view|show|list|switch|create|merge|rebase|stage|restore|reset|stash|search|find|print|copy|move|remove|install|start|cd|git|pnpm|npm|yarn|bun|node|python|python3|bash|sh)\b)/i;
const DISCORD_INTERNAL_CHANNEL_LINE_RE = /^(?:>\s*)?(?:analysis|commentary|tool[-_ ]?call|tool[-_ ]?result|function[-_ ]?call|thinking|reasoning)\s*[:=]/i;
RAW_BUFFERClick to expand / collapse

Summary

Internal tool-call narration lines like 🛠️ print lines 1-260 from memory/2026-05-27.md (agent) and 🩹 Apply Patch are reaching end users via WhatsApp. The Discord outbound adapter strips these via stripDiscordInternalTraceLines + stripDiscordInternalRuntimeScaffolding, but the WhatsApp outbound adapter has no equivalent stripper, so they pass through to recipients.

Versions

  • openclaw 2026.5.22
  • @openclaw/whatsapp 2026.5.5
  • Node 25.9.0, Ubuntu 24.04

Repro / evidence

Operator (carter, hayek host) saw these consecutive WhatsApp messages from his account at 9:10–9:11 AM ET on 2026-05-27:

🛠️ print lines 1-260 from memory/2026-05-27.md (agent)
🛠️ run test memory/2026-05-26.md → print lines 1-220 from memory/2026-05-26.md → run true (agent)
🛠️ print lines 1-260 from BOOTSTRAP.md (agent)
🩹 Apply Patch

The format matches what dist/tool-display-common-D5L_bf7a.js produces:

  • summarizeExecCommandprint lines 1-260 from <path>, joining staged pipelines with
  • classifyWorkspacePath / formatCwdSuffix → trailing (agent) for paths under .openclaw/workspace/
  • 🩹 Apply Patch from the apply_patch entry in the tool-display config

Root cause

WhatsApp's outbound adapter (@openclaw/whatsapp/dist/outbound-adapter-CxwUJNMD.js, lines 15–27) builds the outbound config via createWhatsAppOutboundBase(...) but supplies no sanitizeText. The base (outbound-base-Bq1UYEK5.js:43) defaults to ({ text }) => normalizeText(text) — whitespace-only normalization, no trace-line stripping.

Compare with Discord (openclaw/dist/outbound-adapter-Bw8wq78A.js:359-366):

const discordOutbound = {
  deliveryMode: "direct",
  chunker: ...,
  textChunkLimit: DISCORD_TEXT_CHUNK_LIMIT,
  sanitizeText: ({ text }) => stripDiscordInternalRuntimeScaffolding(text),
  ...
};

…and reply-delivery-mSl5EGCh.js:67-83 (stripDiscordInternalTraceLines) which strips lines matching:

const DISCORD_INTERNAL_TRACE_LINE_RE = /^(?:>\s*)?(?:📊|🛠️|📖|📝|🔍|🔎|⚙️)\s*(?:Session Status|Exec|Read|Edit|Write|Patch|Search|Open|Click|Find|Screenshot|Update Plan|Tool Call|Tool Result|Function Call|Shell|Command)\s*:/i;
const DISCORD_INTERNAL_COMPACT_COMMAND_TRACE_LINE_RE = /^(?:>\s*)?🛠️\s*(?:(?:(?:elevated|pty)\b\s*(?:·|,)\s*)+)?(?:`{1,2}\s*\S|(?:run|check|fetch|pull|push|view|show|list|switch|create|merge|rebase|stage|restore|reset|stash|search|find|print|copy|move|remove|install|start|cd|git|pnpm|npm|yarn|bun|node|python|python3|bash|sh)\b)/i;
const DISCORD_INTERNAL_CHANNEL_LINE_RE = /^(?:>\s*)?(?:analysis|commentary|tool[-_ ]?call|tool[-_ ]?result|function[-_ ]?call|thinking|reasoning)\s*[:=]/i;

These constants are named DISCORD_* and live inside extensions/discord/... even though the content they filter is not Discord-specific — it's a generic openclaw tool-display artifact that every channel should hide.

Suggested fix

  1. Promote the three trace-line regexes and the stripInternalTraceLines helper out of the Discord extension into a channel-agnostic location (e.g. plugin-sdk/text-runtime or alongside sanitizeAssistantVisibleText).
  2. Apply the helper in the WhatsApp outbound adapter's sanitizeText (and audit Signal, Nostr, Telegram, Matrix etc. for the same gap — only Discord currently has it).
  3. Optional: keep the Discord-specific scaffolding stripper (<system-reminder> / <previous_response> tags) Discord-only since those XML-ish blocks are more Discord-flavored markdown concerns.

Why it matters

WhatsApp groups containing non-operators see these lines and read them as broken/leaked agent diagnostics. There is no operator-facing toggle that suppresses them on WhatsApp today — channels.whatsapp.reactionLevel, streaming.mode, etc. don't gate this output, because the lines arrive embedded in the assistant's final text body, not as streaming/progress chunks.

Workarounds for operators

Until fixed: monkey-patch @openclaw/whatsapp/dist/outbound-adapter-CxwUJNMD.js to pass sanitizeText: ({ text }) => stripDiscordInternalRuntimeScaffolding(text) into createWhatsAppOutboundBase(...) (requires re-applying after each npm update -g openclaw).

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix WhatsApp delivery leaks internal tool-trace lines (🛠️/🩹) that Discord strips