fix(slack): duplicate replies and missing streaming recipient params#20623
Closed
rahulsub-be wants to merge 2 commits intoopenclaw:mainfrom
Closed
fix(slack): duplicate replies and missing streaming recipient params#20623rahulsub-be wants to merge 2 commits intoopenclaw:mainfrom
rahulsub-be wants to merge 2 commits intoopenclaw:mainfrom
Conversation
…uplicate replies When streaming is disabled, the deliver callback reads draftStream.messageId() to decide whether to finalize via chat.update (edit-in-place) or fall through to deliverReplies (post new message). For fast model responses (e.g. Haiku), the agent finishes before the draft stream's throttled send() resolves, causing messageId() to return undefined. This makes canFinalizeViaPreviewEdit false, so deliverReplies posts a new message. Then draftStream.flush() fires the pending draft, producing a second (edited) message — the duplicate. The fix adds `await draftStream?.flush()` at the top of the deliver callback, ensuring the draft stream's pending send/edit operations complete before messageId() is read. Closes #19373 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tStream Slack's streaming API (chat.startStream) requires recipient_team_id and recipient_user_id when streaming outside of DMs. Without these parameters, the API returns a missing_recipient_team_id error, causing the stream to fail entirely and no replies to be delivered. This adds optional teamId and userId parameters to StartSlackStreamParams and passes them through to client.chatStream() as recipient_team_id and recipient_user_id. The call site in dispatch.ts now supplies ctx.teamId (from auth.test) and message.user. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Thanks for the PR. Related Slack streaming fix merged in #20988: https://github.com/openclaw/openclaw/pull/20988\n\nSince this one is currently open/conflicting, maintainers may want to close/supersede or rebase only the remaining deltas. |
This was referenced Feb 21, 2026
|
This pull request has been automatically marked as stale due to inactivity. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
missing_recipient_team_iderror fromchat.startStreampreventing native streaming from working outside DMs.await draftStream?.flush()before readingmessageId()in the deliver callback to ensure the draft stream's pending operations complete first. (2) Addedrecipient_team_idandrecipient_user_idparams tostartSlackStream()and passed them through toclient.chatStream().Change Type (select all)
Scope (select all touched areas)
Linked Issue/PR
User-visible / Behavior Changes
chat.startStream/chat.appendStream/chat.stopStream) now works in channels and threads, not just DMs.Security Impact (required)
NoNoNo— same Slack API calls, just with additional optional parametersNoNoRepro + Verification
Environment
channels.slack.streaming: falsefor bug 1,channels.slack.streaming: truefor bug 2Steps
Bug 1 (duplicate replies):
streaming: falsein Slack configBug 2 (streaming failure):
streaming: truein Slack configmissing_recipient_team_iderror in logs, no reply deliveredExpected
Actual (before fix)
missing_recipient_team_iderror when streaming is enabled outside DMsEvidence
Bug 1 root cause: The
delivercallback indispatch.tsreadsdraftStream.messageId()to decide whether to finalize viachat.update(edit-in-place) or fall through todeliverReplies(post new message). For fast model responses, the agent completes before the draft stream's 1000ms throttledsend()resolves, somessageId()returnsundefined,canFinalizeViaPreviewEditis false, anddeliverRepliesposts a new message. ThendraftStream.flush()at line 391 fires the pending draft — producing a second "(edited)" message.Bug 2 root cause: Slack's
chat.startStreamAPI requiresrecipient_team_id(and optionallyrecipient_user_id) when streaming outside of DMs. The@slack/web-apiSDK'sChatStartStreamArgumentstype includes these as optional params, butstartSlackStream()wasn't passing them.Human Verification (required)
streaming: false— single reply each time (no more duplicates)streaming: true— streaming works, nomissing_recipient_team_iderrorsteamId(gracefully omitted from API call via conditional spread)recipient_team_id/recipient_user_idare optional)Compatibility / Migration
YesNoNoFailure Recovery (if this breaks)
streaming: falsein Slack config to disable streaming; the duplicate fix has no config toggle but is a safe no-op (flushing an already-flushed stream is idempotent)src/slack/streaming.ts,src/slack/monitor/message-handler/dispatch.tsflush()introduces latency, final reply delivery could be slightly delayed (bounded by the draft stream's throttle interval, typically 1s)Risks and Mitigations
await draftStream?.flush()in the deliver callback could add up to ~1s latency on the final reply if the draft stream has a pending throttled send.🤖 AI-assisted (Claude Opus 4.6 via Claude Code). Both fixes fully tested locally with real Slack workspace.
Greptile Summary
Fixes two distinct Slack messaging bugs: duplicate replies when streaming is disabled and streaming failures in channels/threads.
Key changes:
await draftStream?.flush()before readingmessageId()indispatch.ts:237to prevent race condition between draft stream throttle and delivery callbackteamIdanduserIdparameters tostartSlackStream()and passed them asrecipient_team_idandrecipient_user_idto Slack'schatStream()APIAnalysis:
The duplicate message bug occurred when fast model responses (like Haiku) completed before the draft stream's 1000ms throttled send resolved, causing
messageId()to return undefined, which then bypassed the preview-edit finalization and triggered a second message viadeliverReplies(). The flush ensures pending operations complete before the message ID check.The streaming failure was straightforward - Slack's streaming API requires
recipient_team_id(and optionallyrecipient_user_id) for channels/threads but not DMs. The parameters are now conditionally passed using spread syntax.Confidence Score: 5/5
Last reviewed commit: 3b69a0c
(2/5) Greptile learns from your feedback when you react with thumbs up/down!