Skip to content

Feishu (and non-Discord channels) should apply sanitizeAssistantVisibleText() on outbound text #90684

Description

@studentzhou-svg

Summary

The sanitizeAssistantVisibleText() pipeline already strips internal XML scaffolding (tool-call tags, thinking tags, model tokens, legacy bracket blocks, etc.) — but it is only applied to Discord today. Feishu and other non-Discord channels send raw text directly, causing <invoke name="exec">, <tool_call>, <function_call> and similar XML tags to leak into user-visible messages.

Reproduction

  1. Use a model that emits XML tool-call scaffolding as plain text (e.g. DeepSeek V4, GLM-5, Kimi through non-native providers)
  2. When the model's exec command fails (e.g. unmatched shell quotes), the stderr contains the original prompt's tool-call XML tags
  3. The assistant sees this error output and may include it in the reply
  4. On Discord this is stripped before delivery; on Feishu/Telegram/WhatsApp it lands in the user's chat

Technical Analysis

What exists today

assistant-visible-text-ye5B62pZ.js exports sanitizeAssistantVisibleText() — a comprehensive pipeline that strips:

  • Model special tokens (<|...|>)
  • Thinking/reasoning/antthinking tags
  • <final> tags
  • <tool_call>, <tool_result>, <function_call>, <function_calls>, <function_response>, <function>, <tool_calls> XML blocks
  • [TOOL_CALL] / [TOOL_RESULT] legacy bracket blocks
  • Minimax tool-call XML (<invoke> with minimax:tool_call namespace)
  • <relevant_memories> tags
  • Downgraded tool-call text ([Tool Call:...] blocks)

Where it's used

Only the Discord channel calls it:

// reply-delivery-DaHJ1mRV.js
function sanitizeDiscordFrontChannelText(text) {
  return collapseExcessBlankLines(
    stripDiscordInternalTraceLines(sanitizeAssistantVisibleText(text))
  ).trim();
}

Where it's missing

Feishu's sendMessageFeishu() in send-BB9NHzC6.js sends raw text directly:

let rawText = text ?? "";
if (mentions && mentions.length > 0) rawText = buildMentionedMessage(mentions, rawText);
// ⬇️ MISSING: rawText = sanitizeAssistantVisibleText(rawText);
const { content, msgType } = buildFeishuPostMessagePayload({
  messageText: convertMarkdownTables(rawText, tableMode)
});

The same issue applies to sendStructuredCardFeishu() and sendMarkdownCardFeishu().

Likely also affects Telegram, WhatsApp, Slack, and other channels that don't apply this pipeline.

Proposed Solution

Option A: Per-channel config flag (minimal)

Add a sanitizeVisibleText boolean config field to the Feishu channel schema (default true), and call sanitizeAssistantVisibleText() before sending.

Option B: Global default (ideal)

Move the sanitization to the shared outbound pipeline (channel-outbound-DuRkxH3q.js or reply-payload-swpu2tGD.js) so all channels benefit automatically. Make it opt-out per channel via config.

Option C: Channel-level config

Add channels.feishu.sanitizeVisibleText and channels.*.sanitizeVisibleText as a standard channel field.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High-priority user-facing bug, regression, or broken workflow.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:needs-security-reviewClawSweeper marked this issue as needing security-sensitive review.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:message-lossChannel message delivery can be lost, duplicated, or misrouted.impact:securitySecurity boundary, credential, authz, sandbox, or sensitive-data risk.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.staleMarked as stale due to inactivity

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions