diff --git a/CHANGELOG.md b/CHANGELOG.md index 68281694d3e..0bd2faa816c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ Docs: https://docs.openclaw.ai - Control UI/WebChat: collapse duplicate in-flight internal text sends onto the active Gateway run so rapid repeat submits do not start fresh `agent:main:main` dispatches. Fixes #75737. Thanks @dsdsddd1 and @BunsDev. - Mattermost: accept the documented `channels.mattermost.streaming` config and honor `streaming: "off"` by disabling draft preview posts. Thanks @vincentkoc. - Mattermost: expose streaming progress config labels and help text in generated channel config metadata so Control UI/docs can explain the new `channels.mattermost.streaming.progress.*` fields. Thanks @vincentkoc. +- Mattermost: honor `channels.mattermost.streaming.progress.toolProgress=false` in progress draft mode so compact tool status lines stay hidden until final delivery. Thanks @vincentkoc. - Discord: keep progress draft boundary callbacks bound during streaming replies, so extension lint stays green while progress previews transition between assistant and reasoning blocks. Thanks @vincentkoc. - Discord: resolve SecretRef-backed bot tokens from the active runtime snapshot for named accounts and keep unresolved configured tokens from crashing status or health checks. (#76987) Thanks @joshavant. - Channels/streaming: expose `streaming.progress.label`, `labels`, `maxLines`, and `toolProgress` in bundled channel config metadata so progress draft settings appear in config, docs, and control surfaces. Thanks @vincentkoc. diff --git a/extensions/mattermost/src/mattermost/monitor.test.ts b/extensions/mattermost/src/mattermost/monitor.test.ts index 8509540c01c..7e72b3a844e 100644 --- a/extensions/mattermost/src/mattermost/monitor.test.ts +++ b/extensions/mattermost/src/mattermost/monitor.test.ts @@ -17,6 +17,7 @@ import { resolveMattermostThreadSessionContext, shouldFinalizeMattermostPreviewAfterDispatch, shouldClearMattermostDraftPreview, + shouldUpdateMattermostDraftToolProgress, type MattermostMentionGateInput, type MattermostRequireMentionResolverInput, } from "./monitor.js"; @@ -266,6 +267,53 @@ describe("canFinalizeMattermostPreviewInPlace", () => { }); }); +describe("shouldUpdateMattermostDraftToolProgress", () => { + type MattermostConfig = NonNullable["mattermost"]>; + + function resolveToolProgressEnabled(mattermostConfig: MattermostConfig) { + const account = resolveMattermostAccount({ + cfg: { + channels: { + mattermost: mattermostConfig, + }, + }, + accountId: "default", + allowUnresolvedSecretRef: true, + }); + return shouldUpdateMattermostDraftToolProgress(account); + } + + it("shows tool status draft lines by default", () => { + expect(resolveToolProgressEnabled({ enabled: true })).toBe(true); + }); + + it("honors disabled progress-mode tool status lines", () => { + expect( + resolveToolProgressEnabled({ + streaming: { + mode: "progress", + progress: { + toolProgress: false, + }, + }, + }), + ).toBe(false); + }); + + it("keeps tool status draft lines disabled when draft streaming is off", () => { + expect( + resolveToolProgressEnabled({ + streaming: { + mode: "off", + progress: { + toolProgress: true, + }, + }, + }), + ).toBe(false); + }); +}); + describe("shouldClearMattermostDraftPreview", () => { it("deletes the preview after successful normal final delivery", () => { expect( diff --git a/extensions/mattermost/src/mattermost/monitor.ts b/extensions/mattermost/src/mattermost/monitor.ts index 729129c2065..291eb34daef 100644 --- a/extensions/mattermost/src/mattermost/monitor.ts +++ b/extensions/mattermost/src/mattermost/monitor.ts @@ -1,4 +1,5 @@ import { deliverFinalizableDraftPreview } from "openclaw/plugin-sdk/channel-lifecycle"; +import { resolveChannelStreamingPreviewToolProgress } from "openclaw/plugin-sdk/channel-streaming"; import { createClaimableDedupe, type ClaimableDedupe } from "openclaw/plugin-sdk/persistent-dedupe"; import { isReasoningReplyPayload } from "openclaw/plugin-sdk/reply-payload"; import { resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/security-runtime"; @@ -8,7 +9,11 @@ import { normalizeOptionalString, } from "openclaw/plugin-sdk/text-runtime"; import { getMattermostRuntime } from "../runtime.js"; -import { resolveMattermostAccount, resolveMattermostReplyToMode } from "./accounts.js"; +import { + resolveMattermostAccount, + resolveMattermostReplyToMode, + type ResolvedMattermostAccount, +} from "./accounts.js"; import { createMattermostClient, fetchMattermostMe, @@ -114,6 +119,14 @@ export type MonitorMattermostOpts = { webSocketFactory?: MattermostWebSocketFactory; }; +export function shouldUpdateMattermostDraftToolProgress( + account: Pick, +): boolean { + return ( + account.streamingMode !== "off" && resolveChannelStreamingPreviewToolProgress(account.config) + ); +} + type MediaKind = "image" | "audio" | "video" | "document" | "unknown"; type MattermostReaction = { @@ -1634,6 +1647,7 @@ export async function monitorMattermostProvider(opts: MonitorMattermostOpts = {} }, }); const draftPreviewEnabled = account.streamingMode !== "off"; + const draftToolProgressEnabled = shouldUpdateMattermostDraftToolProgress(account); const draftStream = draftPreviewEnabled ? createMattermostDraftStream({ client, @@ -1848,6 +1862,9 @@ export async function monitorMattermostProvider(opts: MonitorMattermostOpts = {} } }, onToolStart: async (payload) => { + if (!draftToolProgressEnabled) { + return; + } draftStream.update(buildMattermostToolStatusText(payload)); }, },