Skip to content

feat(slack): add threadDirectMessages option - #776

Closed
dancer wants to merge 3 commits into
mainfrom
josh/slack-thread-dms
Closed

feat(slack): add threadDirectMessages option#776
dancer wants to merge 3 commits into
mainfrom
josh/slack-thread-dms

Conversation

@dancer

@dancer dancer commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

summary

adds threadDirectMessages to SlackAdapterConfig. when enabled, a top-level DM becomes its own thread root and the bot replies inside that thread, instead of every message and reply landing in one flat DM transcript

const slack = createSlackAdapter({ threadDirectMessages: true })

it also gives DMs the thread_ts that slack's native streaming api requires. chat.startStream documents thread_ts as required, and the adapter's stream() returns null on an empty threadTs, so a flat DM could never stream natively and always fell back to post-and-edit. threaded DMs stream natively, which is the gap described in #503

agentView already threaded DMs, but only as part of the full agents setup (manifest agent_view, assistant:write, chat tab). that behavior is now available on its own, and agentView implies it

behavior

thread id reply
default slack:D123: flat in the DM
threadDirectMessages: true slack:D123:{ts} in a thread under the user's message

defaults to false. thread ids are storage keys, so flipping the default would orphan existing subscriptions and per-thread state for every deployed slack bot

subscriptions keep working. the existing openDM() bridge is reused, so when the conversation-scoped thread is subscribed, top-level DMs still route to it and onSubscribedMessage and proactive flows are unaffected

channels are untouched

implementation

the two agentView gates in handleMessageEvent now read a combined dmThreading flag:

this.dmThreading = this.agentView || (config.threadDirectMessages ?? false)

const threadTs =
  isDM && !this.dmThreading
    ? event.thread_ts || ""
    : event.thread_ts || event.ts

the remaining agentView checks (app_home tab handling, suggested prompts) are agents-ui concerns and stay as they are

test plan

  • a top-level DM threads under its own ts when the option is on
  • DM replies stay on the parent thread_ts
  • a top-level DM routes to the conversation-scoped thread when it is subscribed, covering the openDM() flow
  • DMs stay conversation-scoped when the option is unset
  • channel threading is unchanged

verified against a real slack workspace over socket mode, on a non-agent app so message.im arrives with no thread_ts:

  • conversations.replies shows the user's own message as the thread root (thread_ts == ts) with the bot reply inside it
  • conversations.history shows only user messages at top level with reply_count: 1, so bot replies no longer sit in the flat DM
  • native streaming engages in a DM, logging chat.startStream with the incoming message ts and no post-and-edit fallback
  • with the option off, the same DM resolves to slack:D...: and the reply lands flat

@dancer
dancer requested a review from a team as a code owner August 3, 2026 11:43
@vercel

vercel Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
chat Ready Ready Preview, v0 Aug 3, 2026 11:44am
chat-sdk-nextjs-chat Ready Ready Preview Aug 3, 2026 11:44am

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant