fix(telegram): hide spaced internal reasoning prefixes

Co-authored-by: WangYan <wang.yan29@xydigit.com>
Punchcard-Session: amber-summit-river-a3
This commit is contained in:
Vincent Koc
2026-08-18 22:46:15 -07:00
parent 220b12880c
commit be0cb02138
3 changed files with 37 additions and 12 deletions
@@ -188,21 +188,34 @@ describeTelegramDispatch("dispatchTelegramMessage reasoning-room-events", () =>
expect(deliverReplies).not.toHaveBeenCalled();
});
it("suppresses internal reflection when reasoning streams", async () => {
const { reasoningDraftStream } = setupDraftStreams({
it("suppresses whitespace-form internal prefixes until one visible final", async () => {
const { answerDraftStream, reasoningDraftStream } = setupDraftStreams({
answerMessageId: 2001,
reasoningMessageId: 3001,
});
mockTurn(async ({ dispatcherOptions }) => {
await dispatcherOptions.deliver(
{ text: "<internal>private reflection</internal>", isReasoning: true },
{ kind: "final" },
);
for (const text of [
"< internal",
"< internal",
"</ internal",
"< / internal",
"<\u00a0internal",
]) {
await dispatcherOptions.deliver({ text, isReasoning: true }, { kind: "block" });
}
expect(reasoningDraftStream.update).not.toHaveBeenCalled();
expect(deliverReplies).not.toHaveBeenCalled();
await dispatcherOptions.deliver({ text: "VISIBLE" }, { kind: "final" });
});
await dispatchWithContext({ context: createReasoningStreamContext() });
expect(reasoningDraftStream.update).not.toHaveBeenCalled();
expect(answerDraftStream.update).toHaveBeenCalledTimes(1);
expect(answerDraftStream.update).toHaveBeenCalledWith(
"VISIBLE",
expect.objectContaining({ onPlatformSendDispatch: expect.any(Function) }),
);
expect(deliverReplies).not.toHaveBeenCalled();
});
@@ -41,9 +41,22 @@ describe("splitTelegramReasoningText", () => {
});
});
it("does not emit partial reasoning tag prefixes", () => {
expect(splitTelegramReasoningText(" <thi", true)).toStrictEqual({});
expect(splitTelegramReasoningText(" <int", true)).toStrictEqual({});
it.each([
" <thi",
" <int",
"< internal",
"< internal",
"</ internal",
"< / internal",
"<\u00a0internal",
])("does not emit partial reasoning tag prefix %j", (text) => {
expect(splitTelegramReasoningText(text, true)).toStrictEqual({});
});
it("keeps unrelated partial tags visible", () => {
expect(splitTelegramReasoningText("< interface", true)).toStrictEqual({
reasoningText: "🧠 _< interface_",
});
});
it("keeps visible Thinking-prefixed answers in the answer lane", () => {
@@ -1,7 +1,6 @@
// Telegram plugin module implements reasoning lane coordinator behavior.
import { formatReasoningMessage } from "openclaw/plugin-sdk/agent-runtime";
import type { ReplyPayload } from "openclaw/plugin-sdk/reply-payload";
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
import {
findCodeRegions,
isInsideCode,
@@ -71,14 +70,14 @@ function extractThinkingFromTaggedStreamOutsideCode(text: string): string {
}
function isPartialReasoningTagPrefix(text: string): boolean {
const trimmed = normalizeLowercaseStringOrEmpty(text.trimStart());
const trimmed = text.trim().replace(/^<\s*(\/?)\s+/u, "<$1");
if (!trimmed.startsWith("<")) {
return false;
}
if (trimmed.includes(">")) {
return false;
}
return REASONING_TAG_PREFIXES.some((prefix) => prefix.startsWith(trimmed));
return REASONING_TAG_PREFIXES.some((prefix) => prefix.startsWith(trimmed.toLowerCase()));
}
type TelegramReasoningSplit = {