fix: prevent reasoning text leak through handleMessageEnd fallback

When enforceFinalTag is active (Google providers), stripBlockTags
correctly returns empty for text without <final> tags. However, the
handleMessageEnd fallback recovered raw text, bypassing this protection
and leaking internal reasoning (e.g. "**Applying single-bot mention
rule**NO_REPLY") to Discord.

Guard the fallback with enforceFinalTag check: if the provider is
supposed to use <final> tags and none were seen, the text is treated
as leaked reasoning and suppressed.

Also harden stripSilentToken regex to allow bold markdown (**) as
separator before NO_REPLY, matching the pattern Gemini Flash Lite
produces.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Mitch McAlister
2026-03-02 19:44:40 +00:00
committed by Peter Steinberger
parent 15677133c1
commit f534ea9906
4 changed files with 38 additions and 5 deletions

View File

@@ -62,6 +62,12 @@ describe("stripSilentToken", () => {
expect(stripSilentToken(" NO_REPLY ")).toBe("");
});
it("strips token preceded by bold markdown formatting", () => {
expect(stripSilentToken("**NO_REPLY")).toBe("");
expect(stripSilentToken("some text **NO_REPLY")).toBe("some text");
expect(stripSilentToken("reasoning**NO_REPLY")).toBe("reasoning");
});
it("works with custom token", () => {
expect(stripSilentToken("done HEARTBEAT_OK", "HEARTBEAT_OK")).toBe("done");
});

View File

@@ -24,7 +24,7 @@ export function isSilentReplyText(
*/
export function stripSilentToken(text: string, token: string = SILENT_REPLY_TOKEN): string {
const escaped = escapeRegExp(token);
return text.replace(new RegExp(`(?:^|\\s+)${escaped}\\s*$`), "").trim();
return text.replace(new RegExp(`(?:^|\\s+|\\*+)${escaped}\\s*$`), "").trim();
}
export function isSilentReplyPrefixText(