fix(slack): enable preview streaming in flat DMs (replyToMode: off) (#76330)

Summary:
- The PR enables Slack draft preview streaming for flat DMs in all non-off modes, updates Slack streaming tests/docs/config metadata/changelog, and refreshes small guard baselines.
- Reproducibility: yes. source-reproducible on current main: the helper returns false for `mode: "partial"` in ...  current test asserts that disabled path. I did not run tests because this review was explicitly read-only.

Automerge notes:
- Ran the ClawSweeper repair loop before final review.
- Included post-review commit in the final squash: fix(slack): enable preview streaming in flat DMs (replyToMode: off)
- Included post-review commit in the final squash: fix(clawsweeper): address review for automerge-openclaw-openclaw-5654…

Validation:
- ClawSweeper review passed for head 52e5d74ef9.
- Required merge gates passed before the squash merge.

Prepared head SHA: 52e5d74ef9
Review: https://github.com/openclaw/openclaw/pull/76330#issuecomment-4365017023

Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: bob <637186+HangGlidersRule@users.noreply.github.com>
This commit is contained in:
clawsweeper[bot]
2026-05-03 01:30:36 +00:00
committed by GitHub
parent 9765a5777c
commit e8df05ed4f
11 changed files with 45 additions and 41 deletions

View File

@@ -111,7 +111,7 @@ export const slackChannelConfigUiHints = {
},
"streaming.nativeTransport": {
label: "Slack Native Streaming",
help: "Enable native Slack text streaming (chat.startStream/chat.appendStream/chat.stopStream) when channels.slack.streaming.mode is partial (default: true). Requires a reply thread target; top-level DMs stay on the non-thread fallback path.",
help: "Enable native Slack text streaming (chat.startStream/chat.appendStream/chat.stopStream) when channels.slack.streaming.mode is partial (default: true). Native streaming and Slack assistant thread status require a reply thread target; top-level DMs can still use draft post-and-edit preview streaming.",
},
"streaming.preview.toolProgress": {
label: "Slack Draft Tool Progress",

View File

@@ -179,35 +179,44 @@ describe("slack native streaming thread hint", () => {
});
describe("slack preview streaming eligibility", () => {
it("stays on for room messages when streaming mode is enabled", () => {
it("stays off when streaming mode is disabled", () => {
expect(
shouldEnableSlackPreviewStreaming({
mode: "partial",
isDirectMessage: false,
}),
).toBe(true);
});
it("stays off for top-level DMs without a reply thread", () => {
expect(
shouldEnableSlackPreviewStreaming({
mode: "partial",
isDirectMessage: true,
mode: "off",
}),
).toBe(false);
});
it("allows DM preview when the reply is threaded", () => {
it("stays on for room messages when streaming mode is enabled", () => {
expect(
shouldEnableSlackPreviewStreaming({
mode: "partial",
isDirectMessage: true,
threadTs: "1000.1",
}),
).toBe(true);
});
it("keeps top-level DMs off even when replyToMode would create a reply thread", () => {
it("allows top-level DM draft previews without a reply thread", () => {
expect(
shouldEnableSlackPreviewStreaming({
mode: "partial",
}),
).toBe(true);
});
it("allows non-partial draft preview modes", () => {
expect(
shouldEnableSlackPreviewStreaming({
mode: "block",
}),
).toBe(true);
expect(
shouldEnableSlackPreviewStreaming({
mode: "progress",
}),
).toBe(true);
});
it("keeps native streaming thread hints separate from draft preview eligibility", () => {
const streamThreadHint = resolveSlackStreamingThreadHint({
replyToMode: "all",
incomingThreadTs: undefined,
@@ -218,10 +227,8 @@ describe("slack preview streaming eligibility", () => {
expect(
shouldEnableSlackPreviewStreaming({
mode: "partial",
isDirectMessage: true,
threadTs: undefined,
}),
).toBe(false);
).toBe(true);
expect(streamThreadHint).toBe("1000.4");
});
});

View File

@@ -117,16 +117,8 @@ export function isSlackStreamingEnabled(params: {
export function shouldEnableSlackPreviewStreaming(params: {
mode: "off" | "partial" | "block" | "progress";
isDirectMessage: boolean;
threadTs?: string;
}): boolean {
if (params.mode === "off") {
return false;
}
if (!params.isDirectMessage) {
return true;
}
return Boolean(params.threadTs);
return params.mode !== "off";
}
export function shouldInitializeSlackDraftStream(params: {
@@ -446,8 +438,6 @@ export async function dispatchPreparedSlackMessage(prepared: PreparedSlackMessag
!sourceRepliesAreToolOnly &&
shouldEnableSlackPreviewStreaming({
mode: slackStreaming.mode,
isDirectMessage: prepared.isDirectMessage,
threadTs: streamThreadHint,
});
const streamingEnabled =
!sourceRepliesAreToolOnly &&