Skip to content

Commit d4d74b7

Browse files
committed
fix(discord): preserve thinking-prefixed progress text
1 parent 86c6cbf commit d4d74b7

2 files changed

Lines changed: 208 additions & 3 deletions

File tree

extensions/discord/src/monitor/message-handler.draft-preview.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -473,13 +473,23 @@ export function createDiscordDraftPreviewController(params: {
473473

474474
function normalizeReasoningProgressLine(text: string): string {
475475
return text
476-
.replace(/^\s*(?:>\s*)?(?:Reasoning:\s*|Thinking(?::\s*|\.{1,3}\s*|\s*(?:\r?\n|\r)\s*))/i, "")
476+
.replace(
477+
/^\s*(?:>\s*)?(?:Reasoning:\s*(?:\r?\n|\r)\s*|Thinking\.{0,3}\s*(?:\r?\n|\r)\s*(?:\r?\n|\r)\s*)/i,
478+
"",
479+
)
477480
.replace(/\s+/g, " ")
478481
.trim();
479482
}
480483

484+
function normalizeReasoningProgressInput(text: string): string {
485+
const normalized = normalizeReasoningProgressLine(text);
486+
const italic = normalized.match(/^_(.*)_$/u);
487+
return (italic?.[1] ?? normalized).trim();
488+
}
489+
481490
function formatReasoningProgressDisplayLine(text: string, maxChars: number): string {
482-
const formatted = normalizeReasoningProgressLine(formatReasoningMessage(text));
491+
const normalizedText = normalizeReasoningProgressInput(text);
492+
const formatted = normalizeReasoningProgressLine(formatReasoningMessage(normalizedText));
483493
if (!formatted) {
484494
return "";
485495
}
@@ -556,7 +566,7 @@ function mergeReasoningProgressText(
556566
}
557567

558568
function isReasoningSnapshotText(text: string): boolean {
559-
return /^\s*(?:>\s*)?(?:Reasoning:\s*|Thinking(?::\s*|\.{1,3}\s*|\s*(?:\r?\n|\r)\s*))/i.test(
569+
return /^\s*(?:>\s*)?(?:Reasoning:\s*(?:\r?\n|\r)\s*|Thinking\.{0,3}\s*(?:\r?\n|\r)\s*(?:\r?\n|\r)\s*)/i.test(
560570
text,
561571
);
562572
}

extensions/discord/src/monitor/message-handler.process.test.ts

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3182,6 +3182,145 @@ describe("processDiscordMessage draft streaming", () => {
31823182
);
31833183
});
31843184

3185+
it("preserves raw reasoning content that starts with Thinking colon", async () => {
3186+
const draftStream = createMockDraftStreamForTest();
3187+
3188+
dispatchInboundMessage.mockImplementationOnce(async (params?: DispatchInboundParams) => {
3189+
await params?.replyOptions?.onToolStart?.({ name: "exec", phase: "start" });
3190+
await params?.replyOptions?.onReasoningStream?.({ text: "Thinking: compare install paths" });
3191+
return createNoQueuedDispatchResult();
3192+
});
3193+
3194+
const ctx = await createAutomaticSourceDeliveryContext({
3195+
discordConfig: {
3196+
streaming: {
3197+
mode: "progress",
3198+
progress: {
3199+
label: "Clawing...",
3200+
},
3201+
},
3202+
},
3203+
});
3204+
3205+
await runProcessDiscordMessage(ctx);
3206+
3207+
expect(draftStream.update).toHaveBeenCalledWith(
3208+
"Clawing...\n\n🛠️ Exec\n• _Thinking: compare install paths_",
3209+
);
3210+
});
3211+
3212+
it("preserves raw reasoning content that starts with Reasoning colon", async () => {
3213+
const draftStream = createMockDraftStreamForTest();
3214+
3215+
dispatchInboundMessage.mockImplementationOnce(async (params?: DispatchInboundParams) => {
3216+
await params?.replyOptions?.onToolStart?.({ name: "exec", phase: "start" });
3217+
await params?.replyOptions?.onReasoningStream?.({ text: "Reasoning: compare install paths" });
3218+
return createNoQueuedDispatchResult();
3219+
});
3220+
3221+
const ctx = await createAutomaticSourceDeliveryContext({
3222+
discordConfig: {
3223+
streaming: {
3224+
mode: "progress",
3225+
progress: {
3226+
label: "Clawing...",
3227+
},
3228+
},
3229+
},
3230+
});
3231+
3232+
await runProcessDiscordMessage(ctx);
3233+
3234+
expect(draftStream.update).toHaveBeenCalledWith(
3235+
"Clawing...\n\n🛠️ Exec\n• _Reasoning: compare install paths_",
3236+
);
3237+
});
3238+
3239+
it("strips legacy Reasoning newline wrappers from progress snapshots", async () => {
3240+
const draftStream = createMockDraftStreamForTest();
3241+
3242+
dispatchInboundMessage.mockImplementationOnce(async (params?: DispatchInboundParams) => {
3243+
await params?.replyOptions?.onToolStart?.({ name: "exec", phase: "start" });
3244+
await params?.replyOptions?.onReasoningStream?.({
3245+
text: "Reasoning:\ncompare install paths",
3246+
});
3247+
return createNoQueuedDispatchResult();
3248+
});
3249+
3250+
const ctx = await createAutomaticSourceDeliveryContext({
3251+
discordConfig: {
3252+
streaming: {
3253+
mode: "progress",
3254+
progress: {
3255+
label: "Clawing...",
3256+
},
3257+
},
3258+
},
3259+
});
3260+
3261+
await runProcessDiscordMessage(ctx);
3262+
3263+
expect(draftStream.update).toHaveBeenCalledWith(
3264+
"Clawing...\n\n🛠️ Exec\n• _compare install paths_",
3265+
);
3266+
});
3267+
3268+
it("strips legacy Thinking ellipsis display wrappers from progress snapshots", async () => {
3269+
const draftStream = createMockDraftStreamForTest();
3270+
3271+
dispatchInboundMessage.mockImplementationOnce(async (params?: DispatchInboundParams) => {
3272+
await params?.replyOptions?.onToolStart?.({ name: "exec", phase: "start" });
3273+
await params?.replyOptions?.onReasoningStream?.({
3274+
text: "Thinking...\n\n_compare install paths_",
3275+
});
3276+
return createNoQueuedDispatchResult();
3277+
});
3278+
3279+
const ctx = await createAutomaticSourceDeliveryContext({
3280+
discordConfig: {
3281+
streaming: {
3282+
mode: "progress",
3283+
progress: {
3284+
label: "Clawing...",
3285+
},
3286+
},
3287+
},
3288+
});
3289+
3290+
await runProcessDiscordMessage(ctx);
3291+
3292+
expect(draftStream.update).toHaveBeenCalledWith(
3293+
"Clawing...\n\n🛠️ Exec\n• _compare install paths_",
3294+
);
3295+
});
3296+
3297+
it("preserves raw reasoning content that starts with a Thinking line", async () => {
3298+
const draftStream = createMockDraftStreamForTest();
3299+
3300+
dispatchInboundMessage.mockImplementationOnce(async (params?: DispatchInboundParams) => {
3301+
await params?.replyOptions?.onToolStart?.({ name: "exec", phase: "start" });
3302+
await params?.replyOptions?.onReasoningStream?.({ text: "Thinking\nthrough the plan" });
3303+
return createNoQueuedDispatchResult();
3304+
});
3305+
3306+
const ctx = await createAutomaticSourceDeliveryContext({
3307+
discordConfig: {
3308+
streaming: {
3309+
mode: "progress",
3310+
progress: {
3311+
label: "Clawing...",
3312+
},
3313+
},
3314+
},
3315+
});
3316+
3317+
await runProcessDiscordMessage(ctx);
3318+
3319+
expect(draftStream.update).toHaveBeenCalledWith(
3320+
"Clawing...\n\n🛠️ Exec\n• _Thinking through the plan_",
3321+
);
3322+
});
3323+
31853324
it("appends raw reasoning chunks that start with Thinking", async () => {
31863325
const draftStream = createMockDraftStreamForTest();
31873326

@@ -3210,6 +3349,62 @@ describe("processDiscordMessage draft streaming", () => {
32103349
);
32113350
});
32123351

3352+
it("appends raw reasoning chunks that start with Thinking ellipsis", async () => {
3353+
const draftStream = createMockDraftStreamForTest();
3354+
3355+
dispatchInboundMessage.mockImplementationOnce(async (params?: DispatchInboundParams) => {
3356+
await params?.replyOptions?.onToolStart?.({ name: "exec", phase: "start" });
3357+
await params?.replyOptions?.onReasoningStream?.({ text: "I was " });
3358+
await params?.replyOptions?.onReasoningStream?.({ text: "Thinking... through the plan" });
3359+
return createNoQueuedDispatchResult();
3360+
});
3361+
3362+
const ctx = await createAutomaticSourceDeliveryContext({
3363+
discordConfig: {
3364+
streaming: {
3365+
mode: "progress",
3366+
progress: {
3367+
label: "Clawing...",
3368+
},
3369+
},
3370+
},
3371+
});
3372+
3373+
await runProcessDiscordMessage(ctx);
3374+
3375+
expect(draftStream.update).toHaveBeenCalledWith(
3376+
"Clawing...\n\n🛠️ Exec\n• _I was Thinking... through the plan_",
3377+
);
3378+
});
3379+
3380+
it("appends raw reasoning chunks that start with Reasoning colon", async () => {
3381+
const draftStream = createMockDraftStreamForTest();
3382+
3383+
dispatchInboundMessage.mockImplementationOnce(async (params?: DispatchInboundParams) => {
3384+
await params?.replyOptions?.onToolStart?.({ name: "exec", phase: "start" });
3385+
await params?.replyOptions?.onReasoningStream?.({ text: "I was " });
3386+
await params?.replyOptions?.onReasoningStream?.({ text: "Reasoning: through edge cases" });
3387+
return createNoQueuedDispatchResult();
3388+
});
3389+
3390+
const ctx = await createAutomaticSourceDeliveryContext({
3391+
discordConfig: {
3392+
streaming: {
3393+
mode: "progress",
3394+
progress: {
3395+
label: "Clawing...",
3396+
},
3397+
},
3398+
},
3399+
});
3400+
3401+
await runProcessDiscordMessage(ctx);
3402+
3403+
expect(draftStream.update).toHaveBeenCalledWith(
3404+
"Clawing...\n\n🛠️ Exec\n• _I was Reasoning: through edge cases_",
3405+
);
3406+
});
3407+
32133408
it("keeps reasoning italics balanced when progress lines truncate", async () => {
32143409
const draftStream = createMockDraftStreamForTest();
32153410

0 commit comments

Comments
 (0)