diff --git a/CHANGELOG.md b/CHANGELOG.md index 71ee4c64e..649eac2d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ Docs: https://docs.openclaw.ai - Telegram/Agents: add inline button `style` support (`primary|success|danger`) across message tool schema, Telegram action parsing, send pipeline, and runtime prompt guidance. (#18241) Thanks @obviyus. - Telegram: surface user message reactions as system events, with configurable `channels.telegram.reactionNotifications` scope. (#10075) Thanks @Glucksberg. - Slack: add configurable streaming modes for draft previews. (#18555) Thanks @Solvely-Colin. +- Slack: add native single-message text streaming with Slack `chat.startStream`/`appendStream`/`stopStream`; keep reply threading aligned with `replyToMode`, default streaming to enabled, and fall back to normal delivery when streaming fails. (#9972) Thanks @natedenh. - Slack: add external-select flow for large argument menus. (#18496) Thanks @Solvely-Colin. - Discord: expose native `/exec` command options (host/security/ask/node) so Discord slash commands get autocomplete and structured inputs. Thanks @thewilloftheshadow. - Discord: allow reusable interactive components with `components.reusable=true` so buttons, selects, and forms can be used multiple times before expiring. Thanks @thewilloftheshadow. diff --git a/src/slack/monitor/message-handler/dispatch.streaming.test.ts b/src/slack/monitor/message-handler/dispatch.streaming.test.ts new file mode 100644 index 000000000..58f4ba069 --- /dev/null +++ b/src/slack/monitor/message-handler/dispatch.streaming.test.ts @@ -0,0 +1,45 @@ +import { describe, expect, it } from "vitest"; +import { isSlackStreamingEnabled, resolveSlackStreamingThreadHint } from "./dispatch.js"; + +describe("slack native streaming defaults", () => { + it("is enabled when config is undefined", () => { + expect(isSlackStreamingEnabled(undefined)).toBe(true); + }); + + it("can be disabled explicitly", () => { + expect(isSlackStreamingEnabled(false)).toBe(false); + expect(isSlackStreamingEnabled(true)).toBe(true); + }); +}); + +describe("slack native streaming thread hint", () => { + it("stays off-thread when replyToMode=off and message is not in a thread", () => { + expect( + resolveSlackStreamingThreadHint({ + replyToMode: "off", + incomingThreadTs: undefined, + messageTs: "1000.1", + }), + ).toBeUndefined(); + }); + + it("uses first-reply thread when replyToMode=first", () => { + expect( + resolveSlackStreamingThreadHint({ + replyToMode: "first", + incomingThreadTs: undefined, + messageTs: "1000.2", + }), + ).toBe("1000.2"); + }); + + it("uses the existing incoming thread regardless of replyToMode", () => { + expect( + resolveSlackStreamingThreadHint({ + replyToMode: "off", + incomingThreadTs: "2000.1", + messageTs: "1000.3", + }), + ).toBe("2000.1"); + }); +});