Skip to content

Mattermost: progress preview overwrites the whole draft per frame instead of merging by line identity (only channel not using mergeChannelProgressDraftLine) #89761

Description

@iloveleon19

Summary

Mattermost is the only streaming channel whose progress preview overwrites the entire draft on every tool/progress frame instead of merging updates onto stable lines by line identity. Every other channel uses the shared mergeChannelProgressDraftLine line-identity helper; Mattermost does not.

Evidence

mergeChannelProgressDraftLine (and the buildChannelProgressDraftLineForEntry / formatChannelProgressDraftText family in src/channels/progress-draft-compositor.ts) is used by:

  • src/channels/streaming.ts, src/channels/progress-draft-compositor.ts (core)
  • extensions/slack/src/monitor/message-handler/dispatch.ts
  • extensions/matrix/src/matrix/monitor/handler.ts
  • extensions/msteams/src/reply-stream-controller.ts

extensions/mattermost has zero usages. Its handlers replace the whole preview each frame:

  • onToolStartdraftStream.update(buildMattermostToolStatusText(...)) — one flat status line, full overwrite (extensions/mattermost/src/mattermost/monitor.ts:1904)
  • onItemEventformatChannelProgressDraftLineForEntry(...) then draftStream.update(progressText) — full overwrite (extensions/mattermost/src/mattermost/monitor.ts:1915)

Impact

Because each frame overwrites the previous text:

  • A tool's start frame and its later update/end frames don't share a line, so progress for one tool replaces (rather than updates) the line for another.
  • Interleaved tools produce churn instead of a stable N-line progress block.
  • The progress.maxLines config (which Mattermost already accepts) can't be honored meaningfully, since there is no maintained list of lines to cap.

Proposed fix

Give Mattermost the same line-identity model the other channels already have:

  1. Maintain a per-turn progressLines array next to the draft stream.
  2. In onToolStart / onItemEvent, build a line with buildChannelProgressDraftLineForEntry(config, { event, itemId, toolCallId, name, phase, ... }) and merge it with mergeChannelProgressDraftLine(progressLines, line, { maxLines: resolveChannelProgressDraftMaxLines(config) }).
  3. Render the merged set with formatChannelProgressDraftText(...) and push that as the single draft update.
  4. Reset the array at onAssistantMessageStart / onReasoningEnd boundaries (same shape Discord/Slack use).

Line id is already itemId ?? toolCallId, so repeated frames for the same tool/item update one line in place. This is line-level grouping inside the existing single Mattermost preview post — not one post per tool.

Prior art / validation

We run exactly this as a local Dockerfile patch against the prebuilt bundle on 2026.5.28 (streaming.mode: "progress", toolProgress: true) and it works: in a production run, 177/177 tool events carried toolCallId, tool lines merged by id (one line per toolCallId), and item/message frames merged by itemId instead of overwriting. Happy to open a PR porting it to the extensions/mattermost source with tests if maintainers are open to it.

Environment

  • OpenClaw: 2026.5.28
  • Mattermost channel, streaming.mode: "progress", progress.toolProgress: true, progress.maxLines: 8

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal backlog priority with limited blast radius.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.clawsweeper:queueable-fixClawSweeper marked this issue as an existing queue_fix_pr work candidate.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:otherThis issue has meaningful maintainer-visible impact outside the owned taxonomy.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions