mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 21:07:01 -06:00
fix(telegram): preserve pre-tool text during CLI tool calls
Preserve Claude CLI commentary outside Telegram’s disposable progress stream so tool-summary collapse cannot erase user-visible pre-tool text. Validated with real-user Telegram E2E and focused regression coverage.
This commit is contained in:
@@ -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" &&
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user