#22485: fix(slack): use threadId from delivery context as threadTs fallback in outbound adapter
channel: slack
size: XS
Cluster:
Agent Messaging Enhancements
## 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
#22982: fix: prevent stale threadId from routing subagent announces to wron...
by unboxed-ai · 2026-02-21
85.1%
#14720: fix(slack): pass threadId in plugin read action (#14706)
by lailoo · 2026-02-12
84.2%
#20406: fix(slack): respect replyToMode when computing statusThreadTs in DMs
by QuinnYates · 2026-02-18
83.8%
#4749: fix: handle string thread IDs in queue drain for Slack
by nvonpentz · 2026-01-30
83.6%
#22216: fix(slack): enable thread reply reading in slack extension plugin
by lan17 · 2026-02-20
82.2%
#5514: Slack: fix threadId ignored on read + thread_broadcast dropped
by SanderHelgesen · 2026-01-31
82.1%
#19083: Slack: preserve per-thread context and consistent thread replies
by jkimbo · 2026-02-17
82.1%
#23320: fix(slack): respect replyToMode when incomingThreadTs is auto-created
by dorukardahan · 2026-02-22
82.0%
#10686: fix(slack): use thread-level sessions for channels to prevent conte...
by pablohrcarvalho · 2026-02-06
82.0%
#23804: fix(slack): preserve string thread context in queue + DM route
by vincentkoc · 2026-02-22
81.8%