← Back to PRs

#22485: fix(slack): use threadId from delivery context as threadTs fallback in outbound adapter

by dorukardahan open 2026-02-21 06:48 View on GitHub →
channel: slack size: XS
## Summary The Slack outbound adapter's `sendText` and `sendMedia` functions only used `replyToId` as the Slack `thread_ts` parameter. The delivery context also carries `threadId` (e.g. from subagent announce flows, gateway `send` RPC), but this field was never destructured or mapped to `threadTs`. This caused subagent completion announcements (`sessions_spawn`) to land in the main Slack DM instead of the originating thread. ## Root Cause In `extensions/slack/src/channel.ts`, the outbound functions destructured `replyToId` but not `threadId`: ```typescript // Before sendText: async ({ to, text, accountId, deps, replyToId, cfg }) => { const result = await send(to, text, { threadTs: replyToId ?? undefined, // threadId ignored }); } ``` The delivery chain (`deliverOutboundPayloads` → `createChannelOutboundContextBase` → `resolveCtx`) correctly propagates `threadId` through to the outbound adapter, but the Slack adapter never reads it. ## Fix Destructure `threadId` and use as fallback: ```typescript // After sendText: async ({ to, text, accountId, deps, replyToId, threadId, cfg }) => { const result = await send(to, text, { threadTs: replyToId ?? threadId ?? undefined, }); } ``` Same for `sendMedia`. ## Testing - Added debug logging to `sendMessageSlack` to trace `threadTs` value - Before fix: `threadTs=NONE` despite `threadId` being present in announce flow - After fix: `threadTs=1771478217.865789` ✅ — announce lands in correct thread Tested with multiple `sessions_spawn` calls from a Slack DM thread. All announcements now correctly route to the originating thread. ## AI Disclosure - [x] AI-assisted (Claude Opus 4.6 via OpenClaw) - [x] Fully tested on live OpenClaw instance - [x] I understand what the code does Fixes #22483 Related: #17731, #22118 <!-- greptile_comment --> <h3>Greptile Summary</h3> Fixes thread routing issue in Slack adapter by adding `threadId` as a fallback to `replyToId` when determining the Slack `thread_ts` parameter. This ensures subagent completion announcements and other flows that only provide `threadId` (not `replyToId`) correctly land in the originating thread rather than the main DM channel. - Destructures `threadId` parameter in both `sendText` and `sendMedia` functions - Uses fallback chain: `replyToId ?? threadId ?? undefined` for `threadTs` - Aligns Slack adapter with Telegram adapter pattern of supporting both fields - Tested with `sessions_spawn` flows to verify announcements now route to correct thread <h3>Confidence Score: 5/5</h3> - This PR is safe to merge with minimal risk - The change is minimal, well-targeted, and follows existing patterns in the codebase. It adds `threadId` as a fallback parameter (already present in the type definition) using a simple nullish coalescing chain. The Telegram adapter uses the same pattern, confirming this is the correct approach. The author has tested the fix with live `sessions_spawn` calls and confirmed the thread routing now works correctly. No breaking changes or side effects expected. - No files require special attention <sub>Last reviewed commit: 289c9a9</sub> <!-- greptile_other_comments_section --> <sub>(4/5) You can add custom instructions or style guidelines for the agent [here](https://app.greptile.com/review/github)!</sub> <!-- /greptile_comment -->

Most Similar PRs