diff --git a/extensions/telegram/src/bot-message-dispatch-reply.ts b/extensions/telegram/src/bot-message-dispatch-reply.ts index d249403e35a6..9cce343fd1c3 100644 --- a/extensions/telegram/src/bot-message-dispatch-reply.ts +++ b/extensions/telegram/src/bot-message-dispatch-reply.ts @@ -336,10 +336,17 @@ export function createTelegramReplyDelivery(params: { !params.draft.isAnswerToolProgressOnly() && !ownedByQueuedRotation && segment.update.text.trimEnd() === params.draft.answerLane.lastPartialText.trimEnd(); + const isDurableProgressCommentary = + params.streamMode === "progress" && + info.kind === "block" && + effectivePayload.isCommentary === true; + // CLI finals exclude separately classified commentary. Send that block outside + // the disposable progress stream or its collapse summary erases the text. const suppressProgressAnswerBlock = params.streamMode === "progress" && info.kind === "block" && segment.lane === "answer" && + !isDurableProgressCommentary && !reply.hasMedia && !hasExecApprovalPayload(effectivePayload) && telegramButtons === undefined; @@ -381,6 +388,7 @@ export function createTelegramReplyDelivery(params: { payload: lanePayload, infoKind: info.kind, buttons: telegramButtons, + allowStream: !isDurableProgressCommentary, }); if ( segment.lane === "answer" && diff --git a/extensions/telegram/src/bot-message-dispatch-turn.ts b/extensions/telegram/src/bot-message-dispatch-turn.ts index 78815dafa812..bf6c6e31cc92 100644 --- a/extensions/telegram/src/bot-message-dispatch-turn.ts +++ b/extensions/telegram/src/bot-message-dispatch-turn.ts @@ -241,6 +241,7 @@ export async function runTelegramDispatchTurn(params: { ? params.progress.commentaryProgressEnabled : undefined, progressPreambleEnabled: params.progress.progressPreambleEnabled, + commentaryPayloadsEnabled: params.progress.progressPreambleEnabled, reasoningPayloadsEnabled: params.draft.durableReasoningPayloadsEnabled, onToolStart: params.progress.handleToolStart, onItemEvent: params.progress.handleItemEvent, diff --git a/extensions/telegram/src/bot-message-dispatch.progress-summary.test.ts b/extensions/telegram/src/bot-message-dispatch.progress-summary.test.ts index afe25a0049fd..a7b26a4aa675 100644 --- a/extensions/telegram/src/bot-message-dispatch.progress-summary.test.ts +++ b/extensions/telegram/src/bot-message-dispatch.progress-summary.test.ts @@ -314,6 +314,36 @@ describeTelegramDispatch("dispatchTelegramMessage progress-summary", () => { ); }); + it("keeps Claude CLI pre-tool commentary after the progress window collapses", async () => { + const markers = "Test markers: caribou-lampion-473, fromage-quantique, satellite-en-tricot"; + const { answerDraftStream } = setupDraftStreams({ answerMessageId: 2001 }); + dispatchReplyWithBufferedBlockDispatcher.mockImplementation( + async ({ dispatcherOptions, replyOptions }) => { + expect(replyOptions?.commentaryPayloadsEnabled).toBe(true); + await replyOptions?.onItemEvent?.({ + kind: "preamble", + itemId: "commentary-1", + progressText: markers, + suppressDurableProgress: true, + }); + await replyOptions?.onBlockReplyQueued?.({ text: markers, isCommentary: true }); + await dispatcherOptions.deliver({ text: markers, isCommentary: true }, { kind: "block" }); + await replyOptions?.onToolStart?.({ name: "Bash", phase: "start" }); + await dispatcherOptions.deliver({ text: "TEST DONE" }, { kind: "final" }); + return { queuedFinal: true }; + }, + ); + + await dispatchWithContext({ + context: createContext(), + streamMode: "progress", + telegramCfg: { streaming: { mode: "progress" } }, + }); + + expectWindowCollapsedTo(answerDraftStream, "🛠️ 1 tool call · ⏱️ 1s"); + expect(allDeliveredReplyTexts()).toEqual([markers, "TEST DONE"]); + }); + it("never streams an interim answer block into the progress window (Discord parity)", async () => { // Progress mode: the window is a pure activity log. An intermediate assistant // answer block (info.kind === "block", before the final) must NOT render into