Skip to content

Commit 1a3ce7c

Browse files
openperfclawsweeper[bot]Takhoffman
authored
fix(qqbot): sanitize outbound text to strip reasoning/thinking content (#90132)
Summary: - Adds QQBot outbound `sanitizeText` wired to `sanitizeAssistantVisibleText` plus a regression test for stripping `<thinking>` and `<think>` blocks. - PR surface: Source +2, Tests +19. Total +21 across 2 files. - Reproducibility: yes. source-reproducible: current main QQBot outbound lacks `sanitizeText`, and shared deli ... nnel text sanitization when that hook exists. I did not run a live Tencent QQBot plus MiniMax reproduction. Automerge notes: - PR branch already contained follow-up commit before automerge: fix(qqbot): add curly braces for eslint(curly) compliance Validation: - ClawSweeper review passed for head 17cf140. - Required merge gates passed before the squash merge. Prepared head SHA: 17cf140 Review: #90132 (comment) Co-authored-by: openperf <16864032@qq.com> Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com> Approved-by: takhoffman Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
1 parent 560b77a commit 1a3ce7c

2 files changed

Lines changed: 21 additions & 0 deletions

File tree

extensions/qqbot/src/channel.message-adapter.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,25 @@ import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
44
import { describe, expect, it, vi } from "vitest";
55
import { qqbotPlugin } from "./channel.js";
66

7+
describe("qqbot outbound sanitizeText", () => {
8+
it("strips reasoning/thinking tags before delivery", () => {
9+
const sanitize = qqbotPlugin.outbound?.sanitizeText;
10+
expect(sanitize).toBeDefined();
11+
if (!sanitize) {
12+
return;
13+
}
14+
15+
const input1 = "<thinking>internal reasoning</thinking>final answer";
16+
expect(sanitize({ text: input1, payload: { text: input1 } })).toBe("final answer");
17+
18+
const input2 = "<think>step by step</think>result";
19+
expect(sanitize({ text: input2, payload: { text: input2 } })).toBe("result");
20+
21+
const input3 = "plain text without tags";
22+
expect(sanitize({ text: input3, payload: { text: input3 } })).toBe("plain text without tags");
23+
});
24+
});
25+
726
const sendTextMock = vi.hoisted(() => vi.fn());
827
const sendMediaMock = vi.hoisted(() => vi.fn());
928

extensions/qqbot/src/channel.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
} from "openclaw/plugin-sdk/channel-outbound";
99
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
1010
import type { ChannelPlugin } from "openclaw/plugin-sdk/core";
11+
import { sanitizeAssistantVisibleText } from "openclaw/plugin-sdk/text-chunking";
1112
// Register the PlatformAdapter before any core/ module is used.
1213
import "./bridge/bootstrap.js";
1314
import { getQQBotApprovalCapability } from "./bridge/approval/capability.js";
@@ -254,6 +255,7 @@ export const qqbotPlugin: ChannelPlugin<ResolvedQQBotAccount> = {
254255
chunker: (text, limit) => getQQBotRuntime().channel.text.chunkMarkdownText(text, limit),
255256
chunkerMode: "markdown",
256257
textChunkLimit: 5000,
258+
sanitizeText: ({ text }) => sanitizeAssistantVisibleText(text),
257259
shouldSuppressLocalPayloadPrompt: ({ cfg, accountId, payload, hint }) =>
258260
shouldSuppressLocalQQBotApprovalPrompt({
259261
cfg,

0 commit comments

Comments
 (0)