Skip to content

feat(slack): add direct message (DM) support#411

Open
duboff wants to merge 6 commits intoColeMurray:mainfrom
chattermill:feat/slack-dm-support
Open

feat(slack): add direct message (DM) support#411
duboff wants to merge 6 commits intoColeMurray:mainfrom
chattermill:feat/slack-dm-support

Conversation

@duboff
Copy link
Copy Markdown
Contributor

@duboff duboff commented Mar 25, 2026

Summary

  • Users can now interact with the bot via direct messages (DMs) without needing to @mention it
  • Handles message.im events with channel_type === "im"
  • Skips bot messages to prevent self-responses
  • Supports the same session management, repo selection, and multi-turn conversation as channel mentions
  • DMs don't have channel metadata (name/description), so those are omitted from context

Test plan

  • Send a DM to the bot with a coding request — verify a session is created
  • Reply in the same DM thread — verify it continues the existing session
  • Test repo selection in DM (if multiple repos configured) — verify it works the same as in channels
  • Verify the bot does not respond to its own messages in DMs

Users can now interact with the bot via direct messages without needing
to @mention it. Handles message.im events with channel_type "im", skips
bot messages to prevent self-responses, and supports the same session
management, repo selection, and multi-turn conversation as channel mentions.

DMs don't have channel metadata (name/description), so those are omitted
from context when building prompts.
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 25, 2026

Greptile Summary

This PR adds direct message (DM) support to the Slack bot by introducing a handleDirectMessage function and a channel_type === "im" dispatch guard in handleSlackEvent. The overall structure is solid and mirrors the existing handleAppMention flow correctly — session lookup, repo classification, KV-backed pending-message storage, and select_repo interop all work as expected for DMs.

Three areas could use polish:

  • Silent empty-message handlinghandleAppMention replies with "Hi! Please include a message with your request." when the text is empty, but handleDirectMessage returns silently. A user sending a blank DM would get no feedback.
  • @mention tokens not stripped — The comment notes that DMs don't need a mention, but users can still type @BotName …. When they do, the raw <@U12345> token is forwarded to the session without stripping, unlike the handleAppMention path.
  • No explicit message-subtype guard — Slack delivers message_changed and message_deleted events with channel_type: "im". The absent top-level user field incidentally prevents them from triggering the handler, but an explicit !event.subtype check (plus adding subtype?: string to the type definition) would make this defence deliberate and resilient to future API changes.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: packages/slack-bot/src/index.ts
Line: 1156-1159

Comment:
**Silent empty-message handling differs from `handleAppMention`**

When `handleAppMention` receives a message with no text it replies with `"Hi! Please include a message with your request."`, giving the user actionable feedback. The DM handler silently returns with only an internal log, so the user sees nothing and has no idea why the bot didn't respond.

```suggestion
  if (!messageText) {
    log.info("slack.dm.empty_message", { trace_id: traceId });
    await postMessage(
      env.SLACK_BOT_TOKEN,
      channel,
      "Hi! Please include a message with your request.",
      { thread_ts: ts }
    );
    return;
  }
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: packages/slack-bot/src/index.ts
Line: 1152-1154

Comment:
**`@mention` syntax not stripped from DM text**

The comment says "the text doesn't have a bot mention to strip," but users *can* still `@mention` the bot inside a DM (e.g., `@Bot please fix the bug`). When they do, the raw Slack mention token (`<@U12345>`) is forwarded verbatim to the session, which may confuse the agent.

Applying the same strip that `handleAppMention` uses prevents this:

```suggestion
  // Strip any bot mention tokens the user may have typed in the DM (uncommon but possible)
  const rawText = event.text || "";
  const messageText = rawText.replace(/<@[A-Z0-9]+>/g, "").trim();
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: packages/slack-bot/src/index.ts
Line: 813-836

Comment:
**No explicit `subtype` guard for DM message events**

Slack delivers every message-related event in an IM channel under `message.im`, including `message_changed` (user edits) and `message_deleted`. Those events omit the top-level `user` field, so the current `event.user` guard incidentally prevents them from being processed — but this is implicit.

Adding an explicit `!event.subtype` check (and surfacing `subtype` in the type definition) makes the intent clear, guards against future Slack API changes, and removes the dependence on the coincidental absence of `user`:

```suggestion
  // Handle direct messages (DMs) to the bot
  // message.im events have channel_type "im" - these are 1:1 DMs with the bot
  if (
    event.type === "message" &&
    !event.subtype &&
    event.channel_type === "im" &&
    event.channel &&
    event.ts &&
    event.user
  ) {
```

You would also need to add `subtype?: string;` to the event payload type at the top of `handleSlackEvent`.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "feat(slack): add direct message (DM) sup..." | Re-trigger Greptile

Copy link
Copy Markdown
Owner

@ColeMurray ColeMurray left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Automated Review]

The feature is correct and the event handling is well-guarded, but the implementation duplicates nearly all of handleAppMention (~280 lines). See inline comments for details.

No tests included. The slack-bot package has no test files at all (pre-existing), but the duplication makes this riskier — a bug fix applied to only one of the two copies would silently regress the other path.

duboff added 3 commits March 26, 2026 19:28
- Strip <@mention> tokens from DM text before processing
- Guard DM dispatch with !event.subtype to skip bot/edited messages
- Add subtype field to event payload type
- Add observability log at start of handleDirectMessage
Extract mention stripping and DM dispatch guard into dm-utils.ts so
they can be unit tested independently of the Cloudflare Worker entry
point. Add 13 tests covering stripMentions and isDmDispatchable.
TypeScript can't narrow the outer event's optional fields through
the isDmDispatchable type guard, so use non-null assertions for
text/user/channel/ts which isDmDispatchable already validated.
Copy link
Copy Markdown
Owner

@ColeMurray ColeMurray left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typecheck + DRY refactor

Extract shared logic into handleIncomingMessage. Both handlers now
clean the text, optionally fetch channel info, and delegate to the
shared function for thread context, session lookup, repo classification,
and session creation.

Also fixes typecheck error (text variable not in scope) and makes
handleDirectMessage params non-optional since isDmDispatchable guards
them.
ColeMurray added a commit that referenced this pull request Mar 28, 2026
Resolve merge conflict in packages/slack-bot/src/index.ts between
PR #411 (DM support) and PR #334 (branch config). Kept all imports
and functionality from both PRs. Removed unused SlackFile type
reference that caused a compilation error.
ColeMurray added a commit that referenced this pull request Mar 28, 2026
## Summary

Rebased version of #411 by @mikhaildubov with merge conflicts resolved
and a compilation fix.

- Users can interact with the bot via DMs without needing to @mention it
- Handles `message.im` events with `channel_type === "im"`
- Skips bot messages to prevent self-responses
- Supports the same session management, repo selection, and multi-turn
conversation as channel mentions
- DMs don't have channel metadata (name/description), so those are
omitted from context
- Refactors `handleAppMention` into shared `handleIncomingMessage` to
DRY the two entry points

### Changes from original PR
- Resolved merge conflict with #334 (branch config)
- Removed undefined `SlackFile` type reference (compilation fix)

Original PR: #411
Original author: @mikhaildubov (all commits preserved)

## Test plan

- [ ] Send a DM to the bot with a coding request — verify a session is
created
- [ ] Reply in the same DM thread — verify it continues the existing
session
- [ ] Test repo selection in DM (if multiple repos configured)
- [ ] Verify the bot does not respond to its own messages in DMs
- [ ] Verify existing @mention flow still works unchanged

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Slack bot now supports direct messages with full message handling,
session management, and clarification capabilities

* **Tests**
* Added comprehensive test coverage for direct message detection and
text processing utilities

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Mikhail Dubov <mikhail@chattermill.io>
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.

2 participants