From cd6d0f9b00f0d7573fd99ce1ea495f582e107402 Mon Sep 17 00:00:00 2001 From: Masato Hoshino Date: Mon, 29 Jun 2026 04:14:35 +0900 Subject: [PATCH] fix(slack): sanitize internal tool-trace lines from outbound text (#97367) Wrap the slack outbound sanitizeText hook with sanitizeAssistantVisibleText so assistant internal tool-trace scaffolding is stripped before delivery, matching the sibling channel fixes under #90684 (Telegram #95774, Google Chat #95084, IRC #97214). --- extensions/slack/src/channel.ts | 2 ++ .../src/outbound-tool-trace-sanitize.test.ts | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 extensions/slack/src/outbound-tool-trace-sanitize.test.ts 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); + }); +});