diff --git a/extensions/slack/src/channel.ts b/extensions/slack/src/channel.ts index 46084d2dfed..d59c7a393ef 100644 --- a/extensions/slack/src/channel.ts +++ b/extensions/slack/src/channel.ts @@ -30,6 +30,7 @@ import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, } from "openclaw/plugin-sdk/string-coerce-runtime"; +import { sanitizeAssistantVisibleText } from "openclaw/plugin-sdk/text-chunking"; import { resolveDefaultSlackAccountId, resolveSlackAccount, @@ -423,6 +424,7 @@ const slackChannelOutbound: ChannelOutboundAdapter = { deliveryMode: "direct", chunker: null, textChunkLimit: SLACK_TEXT_LIMIT, + sanitizeText: ({ text }) => sanitizeAssistantVisibleText(text), normalizePayload: ({ payload, cfg, accountId }) => isSlackInteractiveRepliesEnabled({ cfg, accountId }) ? compileSlackInteractiveReplies(payload) diff --git a/extensions/slack/src/outbound-tool-trace-sanitize.test.ts b/extensions/slack/src/outbound-tool-trace-sanitize.test.ts new file mode 100644 index 00000000000..681ff785433 --- /dev/null +++ b/extensions/slack/src/outbound-tool-trace-sanitize.test.ts @@ -0,0 +1,19 @@ +// Slack outbound must strip assistant internal tool-trace scaffolding, matching +// the sibling channel fixes tracked under #90684 (Telegram #95774 / Google Chat +// #95084 / IRC #97214). sanitizeAssistantVisibleText keeps mrkdwn formatting. +import { describe, expect, it } from "vitest"; +import { slackPlugin } from "./channel.js"; + +describe("slack outbound sanitizeText", () => { + it("strips internal tool-trace banners before outbound delivery", () => { + const text = "Done.\n⚠️ 🛠️ `search repos (agent)` failed"; + + expect(slackPlugin.outbound?.sanitizeText?.({ text, payload: { text } })).toBe("Done."); + }); + + it("preserves ordinary assistant prose while sanitizing", () => { + const text = "The pipeline has 3 open deals."; + + expect(slackPlugin.outbound?.sanitizeText?.({ text, payload: { text } })).toBe(text); + }); +});