fix(discord): strip reasoning tags from partial stream preview
When streamMode is "partial", reasoning/thinking block content can leak into the Discord draft preview because the partial text is forwarded to the draft stream without filtering. Apply `stripReasoningTagsFromText` before updating the draft and skip pure-reasoning messages (those starting with "Reasoning:\n") so internal thinking traces never reach the user-visible preview. Fixes #24532 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
committed by
Peter Steinberger
parent
0ded77ca7d
commit
e8a4d5d9bd
@@ -30,6 +30,7 @@ import { convertMarkdownTables } from "../../markdown/tables.js";
|
||||
import { buildAgentSessionKey } from "../../routing/resolve-route.js";
|
||||
import { resolveThreadSessionKeys } from "../../routing/session-key.js";
|
||||
import { buildUntrustedChannelMetadata } from "../../security/channel-metadata.js";
|
||||
import { stripReasoningTagsFromText } from "../../shared/text/reasoning-tags.js";
|
||||
import { truncateUtf16Safe } from "../../utils.js";
|
||||
import { chunkDiscordTextWithMode } from "../chunk.js";
|
||||
import { resolveDiscordDraftStreamingChunking } from "../draft-chunking.js";
|
||||
@@ -485,7 +486,13 @@ export async function processDiscordMessage(ctx: DiscordMessagePreflightContext)
|
||||
if (!draftStream || !text) {
|
||||
return;
|
||||
}
|
||||
if (text === lastPartialText) {
|
||||
// Strip reasoning/thinking tags that may leak through the stream.
|
||||
const cleaned = stripReasoningTagsFromText(text, { mode: "strict", trim: "both" });
|
||||
// Skip pure-reasoning messages (e.g. "Reasoning:\n…") that contain no answer text.
|
||||
if (!cleaned || cleaned.startsWith("Reasoning:\n")) {
|
||||
return;
|
||||
}
|
||||
if (cleaned === lastPartialText) {
|
||||
return;
|
||||
}
|
||||
hasStreamedMessage = true;
|
||||
@@ -493,30 +500,30 @@ export async function processDiscordMessage(ctx: DiscordMessagePreflightContext)
|
||||
// Keep the longer preview to avoid visible punctuation flicker.
|
||||
if (
|
||||
lastPartialText &&
|
||||
lastPartialText.startsWith(text) &&
|
||||
text.length < lastPartialText.length
|
||||
lastPartialText.startsWith(cleaned) &&
|
||||
cleaned.length < lastPartialText.length
|
||||
) {
|
||||
return;
|
||||
}
|
||||
lastPartialText = text;
|
||||
draftStream.update(text);
|
||||
lastPartialText = cleaned;
|
||||
draftStream.update(cleaned);
|
||||
return;
|
||||
}
|
||||
|
||||
let delta = text;
|
||||
if (text.startsWith(lastPartialText)) {
|
||||
delta = text.slice(lastPartialText.length);
|
||||
let delta = cleaned;
|
||||
if (cleaned.startsWith(lastPartialText)) {
|
||||
delta = cleaned.slice(lastPartialText.length);
|
||||
} else {
|
||||
// Streaming buffer reset (or non-monotonic stream). Start fresh.
|
||||
draftChunker?.reset();
|
||||
draftText = "";
|
||||
}
|
||||
lastPartialText = text;
|
||||
lastPartialText = cleaned;
|
||||
if (!delta) {
|
||||
return;
|
||||
}
|
||||
if (!draftChunker) {
|
||||
draftText = text;
|
||||
draftText = cleaned;
|
||||
draftStream.update(draftText);
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user