Skip to content

fix(slack): DM thread attachments stay in thread when sent via message tool#38410

Closed
Taskle wants to merge 110 commits intoopenclaw:mainfrom
Taskle:fix/slack-dm-thread-attachment-injection
Closed

fix(slack): DM thread attachments stay in thread when sent via message tool#38410
Taskle wants to merge 110 commits intoopenclaw:mainfrom
Taskle:fix/slack-dm-thread-attachment-injection

Conversation

@Taskle
Copy link
Copy Markdown
Contributor

@Taskle Taskle commented Mar 6, 2026

Fixes #38409

What changed

Two files, minimal diff. All existing tests pass; 21 new assertions added.

src/slack/threading-tool-context.ts

buildSlackThreadingToolContext was discarding currentChannelId for DMs because it only handled channel:xxx-prefixed To values. DM sessions have To = "user:U0AC3LBA08M", so currentChannelId was always undefined.

Fix: also preserve user:xxx addresses as currentChannelId for DMs.

src/infra/outbound/message-action-params.ts

resolveSlackAutoThreadId exited early when currentChannelId was undefined (which it always was in DMs — see above), and even if that were fixed it rejected user: targets with kind !== "channel".

Fix: build a canonical target address ("user:<id>" for DMs, raw channel ID for channels) and compare against currentChannelId, removing the channel-only kind guard.

Why auto-replies were unaffected

deliverReplies uses replyPlan.nextThreadTs() which applies the isThreadReply → "all" override directly, never calling resolveSlackAutoThreadId. Only explicit message tool sends (TTS audio, images, file uploads) went through the broken path.

Test coverage

File Cases
src/slack/threading-tool-context.test.ts +3 (channel prefix strip, DM user: preserve, absent To)
src/infra/outbound/message-action-params.test.ts (new) 11 (channel hit/miss, DM hit/miss, cross-target isolation, replyToMode gating, missing-context guards)
✓ src/slack/threading-tool-context.test.ts (10 tests)
✓ src/infra/outbound/message-action-params.test.ts (11 tests)
Tests: 21 passed

@openclaw-barnacle openclaw-barnacle bot added channel: slack Channel integration: slack size: S labels Mar 6, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 6, 2026

Greptile Summary

This PR fixes a two-part bug that caused DM thread attachments (TTS audio, images, file uploads sent via the message tool) to escape their thread and land in the top-level DM instead of staying in-thread.

Root cause:

  • buildSlackThreadingToolContext only stripped channel:xxx prefixes from To, leaving DM sessions (which use To = "user:Uxxx") with currentChannelId = undefined.
  • resolveSlackAutoThreadId returned early when currentChannelId was undefined, and even if it had been set, the kind !== "channel" guard would have rejected user targets anyway.

Fix summary:

  • threading-tool-context.ts: Preserve the full user:xxx string as currentChannelId for DM sessions (instead of falling through to undefined).
  • message-action-params.ts: Build a canonical comparison address — raw channel ID for channel targets, user:<id> for user targets — removing the kind !== "channel" guard that was never appropriate for DMs.

The fix is minimal, well-targeted, and consistent with the existing asymmetric storage format (currentChannelId stores a raw channel ID for channels and a prefixed user:xxx string for DMs). The test coverage is thorough, covering channel/DM hit and miss, cross-target isolation, replyToMode gating, and missing-context guards.

Confidence Score: 5/5

  • This PR is safe to merge — it's a targeted bug fix with no side effects on existing channel threading behaviour.
  • The changes are minimal (two small logic fixes), the root cause and fix are clearly explained, MessagingTargetKind is exhaustively "user" | "channel" so the ternary in resolveSlackAutoThreadId covers all cases, and the 21 new test assertions directly exercise the regression path plus all boundary conditions. No existing test coverage was removed.
  • No files require special attention.

Last reviewed commit: 6194218

…ge tool

When an agent is in a Slack DM thread and sends an attachment (image, audio,
file) via the message tool, the attachment was posted outside the thread as a
new top-level message instead of continuing in the existing thread.

Root cause: two gaps in the DM thread context chain:

1. buildSlackThreadingToolContext set currentChannelId = undefined for DMs
   because it only extracted the channel ID from 'channel:xxx' prefixed To
   values. DM To values use the 'user:xxx' format, so currentChannelId was
   always undefined in direct messages.

2. resolveSlackAutoThreadId bailed early if parsedTarget.kind !== 'channel',
   which excluded user: targets (kind='user') used for DMs.

Together these meant resolveSlackAutoThreadId always returned undefined in DMs,
so the message tool never injected thread_ts when uploading files — even when
the bot was actively replying in a DM thread.

The auto-reply path (deliverReplies) was unaffected because it uses a separate
replyPlan that correctly applies the isThreadReply override. Only explicit
message tool sends (images, TTS audio, attachments) were broken.

Fix:
- buildSlackThreadingToolContext: preserve 'user:xxx' as currentChannelId for
  DM sessions so downstream matching works.
- resolveSlackAutoThreadId: build a canonical target address ('user:xxx' for
  DMs, raw channel ID for channels) and compare against currentChannelId,
  removing the channel-only kind guard.

Tests: 21 new assertions covering channel threads, DM threads, cross-target
isolation, replyToMode gating, and missing-context guards.
@hnykda
Copy link
Copy Markdown
Contributor

hnykda commented Mar 9, 2026

Tested on Mattermost (applied custom patch with same root cause fix). Can confirm: the duplicate message delivery issue is fixed ✅.

ngutman and others added 20 commits March 13, 2026 20:01
…ssion error (openclaw#39435)

* fix(setup-podman): cd to TMPDIR before podman load to avoid inherited cwd permission error

* fix(podman): safe cwd in run_as_user to prevent chdir errors

Co-Authored-By: Claude Opus 4.6  <[email protected]>
Signed-off-by: sallyom <[email protected]>

---------

Signed-off-by: sallyom <[email protected]>
Co-authored-by: sallyom <[email protected]>
Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
…d minimal prompt mode (openclaw#40204)

* fix(cron): consolidate announce delivery and detach manual runs

* fix: queue detached cron runs (openclaw#40204)
…enclaw#40281)

Merged via squash.

- Local validation: `pnpm exec vitest run --config vitest.gateway.config.ts src/gateway/server-methods/nodes.invoke-wake.test.ts`
- Local validation: `pnpm build`
- mb-server validation: `pnpm exec vitest run --config vitest.gateway.config.ts src/gateway/server-methods/nodes.invoke-wake.test.ts`
- mb-server validation: `pnpm build`
- mb-server validation: `pnpm protocol:check`
…#40282)

Merged via squash.

- mb-server validation: `swift test --package-path apps/shared/OpenClawKit --filter GatewayNodeSessionTests`
- mb-server validation: `pnpm build`
- Scope note: top-level `RootTabs` shell change was intentionally removed from this PR before merge
…rmissive hosts (openclaw#39449)

* fix(run-openclaw-podman): add SELinux :Z mount option on Linux with enforcing/permissive SELinux

* fix(quadlet): add SELinux :Z label to openclaw.container.in volume mount

* fix(podman): add SELinux :Z mount option for Fedora/RHEL hosts

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: sallyom <[email protected]>

---------

Signed-off-by: sallyom <[email protected]>
Co-authored-by: sallyom <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
* Docker: shrink runtime image payload

* Docker: add runtime pnpm opt-in

* Docker: collapse helper entrypoint chmod layers

* Docker: restore bundled pnpm runtime

* Update CHANGELOG.md
…0342)

* docs(changelog): move post-2026.3.8 entries to unreleased

* Update CHANGELOG.md
…claw#40345)

* fix(tui): improve colour contrast for light-background terminals (openclaw#38636)

Detect light terminal backgrounds via COLORFGBG and apply a WCAG
AA-compliant light palette. Adds OPENCLAW_THEME=light|dark env var
override for terminals without auto-detection.

Uses proper sRGB linearisation and WCAG 2.1 contrast ratios to pick
whichever text palette (dark or light) has higher contrast against
the detected background colour.

Co-authored-by: ademczuk <[email protected]>

* Update CHANGELOG.md

---------

Co-authored-by: ademczuk <[email protected]>
Co-authored-by: ademczuk <[email protected]>
@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

2 similar comments
@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

23 similar comments
@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling app: android App: android app: ios App: ios app: macos App: macos app: web-ui App: web-ui channel: bluebubbles Channel integration: bluebubbles channel: discord Channel integration: discord channel: feishu Channel integration: feishu channel: googlechat Channel integration: googlechat channel: imessage Channel integration: imessage channel: irc channel: line Channel integration: line channel: matrix Channel integration: matrix channel: mattermost Channel integration: mattermost channel: msteams Channel integration: msteams channel: nextcloud-talk Channel integration: nextcloud-talk channel: nostr Channel integration: nostr channel: signal Channel integration: signal channel: slack Channel integration: slack channel: telegram Channel integration: telegram channel: tlon Channel integration: tlon channel: twitch Channel integration: twitch channel: voice-call Channel integration: voice-call channel: whatsapp-web Channel integration: whatsapp-web channel: zalo Channel integration: zalo channel: zalouser Channel integration: zalouser cli CLI command changes commands Command implementations docker Docker and sandbox tooling docs Improvements or additions to documentation extensions: acpx extensions: copilot-proxy Extension: copilot-proxy extensions: diagnostics-otel Extension: diagnostics-otel extensions: google-gemini-cli-auth Extension: google-gemini-cli-auth extensions: llm-task Extension: llm-task extensions: lobster Extension: lobster extensions: memory-core Extension: memory-core extensions: memory-lancedb Extension: memory-lancedb extensions: minimax-portal-auth extensions: open-prose Extension: open-prose gateway Gateway runtime scripts Repository scripts size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Slack DM thread attachments posted outside thread when sent via message tool