fix(cli): avoid duplicate commentary delivery (#115596)

This commit is contained in:
Peter Steinberger
2026-07-29 01:40:55 -04:00
committed by GitHub
parent 520e9fe1dd
commit a3a969be5d
5 changed files with 67 additions and 5 deletions
@@ -209,6 +209,7 @@ export type GetReplyOptions = {
meta?: string;
approvalId?: string;
approvalSlug?: string;
suppressDurableProgress?: true;
}) => Promise<ProgressCallbackResult> | ProgressCallbackResult;
/**
* Called when the utility-model narration of the in-progress turn changes.
@@ -257,6 +257,8 @@ export async function runCliFallbackCandidate(params: {
itemId: payload.itemId,
kind: "preamble",
progressText: payload.text,
// The block bridge owns durability; this event remains a progress preview.
...(bridgeCliDurableCommentary ? { suppressDurableProgress: true } : {}),
}),
);
}
@@ -188,6 +188,7 @@ describe("executeAgentTurn: CLI durable commentary", () => {
itemId: "commentary-durable-1",
kind: "preamble",
progressText: "The durable findings live here.",
suppressDurableProgress: true,
});
});
expect(result.kind).toBe("success");
@@ -422,14 +422,18 @@ export async function prepareDispatchExecution(state: ChooseDispatchRouteReadySt
suppressAutomaticSourceDelivery &&
allowSuppressedSourceProgressCallbacks &&
canForwardItemEvents;
const shouldDeliverDurableCommentaryProgress = (
payload: Parameters<NonNullable<GetReplyOptions["onItemEvent"]>>[0],
) =>
deliverStandaloneCommentaryProgress &&
payload.kind === "preamble" &&
payload.suppressDurableProgress !== true;
const forwardItemEvent = canForwardItemEvents
? wrapProgressCallback(params.replyOptions?.onItemEvent, {
...itemEventForwardingOptions,
waitForDirectBlockReplyDelivery: true,
onForward: (payload) =>
preserveProgressCallbackStartOrder &&
deliverStandaloneCommentaryProgress &&
payload.kind === "preamble"
preserveProgressCallbackStartOrder && shouldDeliverDurableCommentaryProgress(payload)
? noteCommentaryProgress(payload)
: undefined,
onVisible: (payload) => {
@@ -453,8 +457,7 @@ export async function prepareDispatchExecution(state: ChooseDispatchRouteReadySt
}
if (
(!forwardItemEvent || !preserveProgressCallbackStartOrder) &&
deliverStandaloneCommentaryProgress &&
payload.kind === "preamble"
shouldDeliverDurableCommentaryProgress(payload)
) {
await noteCommentaryProgress(payload);
}
@@ -92,6 +92,61 @@ describe("dispatchReplyFromConfig", () => {
expect(activeDuringOffRun).toBe(false);
});
it("keeps block-owned commentary out of the standalone durable progress lane", async () => {
setNoAbort();
sessionStoreMocks.currentEntry = {
verboseLevel: "on",
};
const dispatcher = createDispatcher();
const ctx = buildTestCtx({
Provider: "discord",
Surface: "discord",
ChatType: "direct",
});
const onItemEvent = vi.fn();
const replyResolver = async (
_ctx: MsgContext,
opts?: GetReplyOptions,
_cfg?: OpenClawConfig,
) => {
await opts?.onItemEvent?.({
itemId: "commentary-1",
kind: "preamble",
progressText: "Inspecting the dispatch path.",
suppressDurableProgress: true,
});
await opts?.onBlockReply?.({ text: "Inspecting the dispatch path." });
return { text: "Done." } satisfies ReplyPayload;
};
await dispatchReplyFromConfig({
ctx,
cfg: emptyConfig,
dispatcher,
replyResolver,
replyOptions: {
suppressDefaultToolProgressMessages: true,
commentaryProgressEnabled: true,
progressPreambleEnabled: true,
commentaryPayloadsEnabled: true,
onItemEvent,
},
});
expect(onItemEvent).toHaveBeenCalledExactlyOnceWith({
itemId: "commentary-1",
kind: "preamble",
progressText: "Inspecting the dispatch path.",
suppressDurableProgress: true,
});
expect(dispatcher.sendToolResult).not.toHaveBeenCalled();
expect(dispatcher.sendBlockReply).toHaveBeenCalledExactlyOnceWith({
text: "Inspecting the dispatch path.",
});
expect(dispatcher.sendFinalReply).toHaveBeenCalledExactlyOnceWith({ text: "Done." });
});
it("forwards channel-owned group progress callbacks while source delivery is suppressed", async () => {
setNoAbort();
sessionStoreMocks.currentEntry = {