Skip to content

Commit 947a719

Browse files
steipetemycarrysun
andcommitted
fix(slack): keep progress drafts in one message
Keep Slack progress-mode drafts on one rolling preview message across assistant and reasoning boundaries while preserving boundary cleanup and the latest visible tool-progress lines. Partial/replace modes still start a fresh draft at assistant boundaries. Co-authored-by: Mike Harrison <[email protected]>
1 parent a71b121 commit 947a719

2 files changed

Lines changed: 48 additions & 3 deletions

File tree

extensions/slack/src/monitor/message-handler/dispatch.preview-fallback.test.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2179,7 +2179,7 @@ describe("dispatchPreparedSlackMessage preview fallback", () => {
21792179
}),
21802180
);
21812181

2182-
expect(draftStream.forceNewMessage).toHaveBeenCalledTimes(1);
2182+
expect(draftStream.forceNewMessage).not.toHaveBeenCalled();
21832183
expect(draftStream.update).toHaveBeenLastCalledWith({
21842184
text: ["Shelling", "• tool one", "• tool two"].join("\n"),
21852185
blocks: [
@@ -2207,6 +2207,48 @@ describe("dispatchPreparedSlackMessage preview fallback", () => {
22072207
expect(deliverRepliesMock).not.toHaveBeenCalled();
22082208
});
22092209

2210+
it("preserves text Slack progress lines after a draft boundary status update", async () => {
2211+
const draftStream = createDraftStreamStub();
2212+
createSlackDraftStreamMock.mockReturnValueOnce(draftStream);
2213+
mockedSlackStreamingMode = "progress";
2214+
mockedSlackDraftMode = "status_final";
2215+
mockedDispatchSequence = [];
2216+
mockedReplyOptionEvents = [
2217+
{ kind: "item", progressText: "tool one" },
2218+
{ kind: "item", progressText: "tool two" },
2219+
{ kind: "assistant_start" },
2220+
{ kind: "partial", text: "partial answer" },
2221+
];
2222+
2223+
await dispatchPreparedSlackMessage(
2224+
createPreparedSlackMessage({
2225+
accountConfig: { streaming: { progress: { label: "Working" } } },
2226+
}),
2227+
);
2228+
2229+
expect(draftStream.forceNewMessage).not.toHaveBeenCalled();
2230+
expect(draftStream.update).toHaveBeenLastCalledWith(
2231+
["Working", "• tool one", "• tool two"].join("\n"),
2232+
);
2233+
});
2234+
2235+
it("forces a new draft message on assistant boundaries in partial mode", async () => {
2236+
const draftStream = createDraftStreamStub();
2237+
createSlackDraftStreamMock.mockReturnValueOnce(draftStream);
2238+
mockedSlackStreamingMode = "partial";
2239+
mockedSlackDraftMode = "replace";
2240+
mockedDispatchSequence = [];
2241+
mockedReplyOptionEvents = [
2242+
{ kind: "partial", text: "first chunk" },
2243+
{ kind: "assistant_start" },
2244+
{ kind: "partial", text: "second chunk" },
2245+
];
2246+
2247+
await dispatchPreparedSlackMessage(createPreparedSlackMessage({}));
2248+
2249+
expect(draftStream.forceNewMessage).toHaveBeenCalledTimes(1);
2250+
});
2251+
22102252
it("can hide raw Slack command progress text by config", async () => {
22112253
const draftStream = createDraftStreamStub();
22122254
createSlackDraftStreamMock.mockReturnValueOnce(draftStream);

extensions/slack/src/monitor/message-handler/dispatch.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1307,7 +1307,7 @@ export async function dispatchPreparedSlackMessage(prepared: PreparedSlackMessag
13071307
return;
13081308
}
13091309
const progressLines =
1310-
useRichProgressDraft && previewToolProgressLines.length === 0
1310+
previewToolProgressLines.length === 0
13111311
? lastNonEmptyPreviewToolProgressLines
13121312
: previewToolProgressLines;
13131313
const previewText = formatChannelProgressDraftText({
@@ -1610,7 +1610,10 @@ export async function dispatchPreparedSlackMessage(prepared: PreparedSlackMessag
16101610
const onDraftBoundary = !shouldUseDraftStream
16111611
? undefined
16121612
: async () => {
1613-
if (hasStreamedMessage) {
1613+
// Progress drafts are one rolling message that's finalized in place.
1614+
// Keep boundary cleanup, but don't clear messageId or the next update
1615+
// posts a new draft instead of editing the existing preview.
1616+
if (hasStreamedMessage && streamMode !== "status_final") {
16141617
draftStream?.forceNewMessage();
16151618
hasStreamedMessage = false;
16161619
appendRenderedText = "";

0 commit comments

Comments
 (0)