Skip to content

feat(slack): mention gating, thread cache, Block Kit, commands#6734

Closed
bennyhodl wants to merge 1 commit into
NousResearch:mainfrom
bennyhodl:slack-enterprise-features
Closed

feat(slack): mention gating, thread cache, Block Kit, commands#6734
bennyhodl wants to merge 1 commit into
NousResearch:mainfrom
bennyhodl:slack-enterprise-features

Conversation

@bennyhodl

Copy link
Copy Markdown
Contributor

What does this PR do?

Overhauls the Slack adapter with enterprise-grade capabilities. The existing inline mention logic, thread tracking sets, and thread context fetcher are replaced with testable, structured utilities extracted into slack_utils.py. New features include per-channel configuration, Block Kit message rendering, connection health monitoring, slash commands, and message edit detection.

+2,500 lines across 4 files (slack.py, slack_utils.py, slack_commands.py, test_slack_approval_buttons.py)

Related Issue

Fixes #

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

Refactors (behavior-preserving replacements of existing code)

  • check_mention_gate() replaces inline mention conditional — pure function returning MentionGateResult with should_respond, was_mentioned, implicit_mention, reason (gateway/platforms/slack_utils.py)
  • ThreadParticipationCache replaces _bot_message_ts / _mentioned_threads sets — LRU OrderedDict with 24h TTL, async lock, account-aware keys (gateway/platforms/slack_utils.py)
  • load_thread_context() + format_thread_context_for_prompt() replaces _fetch_thread_context() — returns ThreadContext / ThreadMessage dataclasses, cursor pagination, preserves bot messages as "Assistant" (gateway/platforms/slack_utils.py)
  • _has_active_session_for_thread() kept as fallback when ThreadParticipationCache misses after restart (gateway/platforms/slack.py)

New features

  • Per-channel configchannels block under gateway.slack with requireMention, allowBots, users, threadHistoryLimit, replyBroadcast overrides. Resolved early via resolve_channel_config() (gateway/platforms/slack_utils.py)
  • Per-channel user authorizationis_user_allowed_in_channel() whitelists user IDs per channel (gateway/platforms/slack_utils.py)
  • Connection health monitoringSlackConnectionState, probe_slack_connection(), is_non_recoverable_slack_error(), stale socket detection via _mark_event_received() (gateway/platforms/slack_utils.py)
  • OAuth scope validationfetch_slack_scopes() + validate_slack_scopes() against required/recommended sets (gateway/platforms/slack_utils.py)
  • Block Kit message renderingsend() wraps every outgoing message in Block Kit section blocks via _content_to_blocks(), matching the pattern that makes send_exec_approval work. Splits on --- for native dividers, handles oversized sections at line boundaries (gateway/platforms/slack.py)
  • Interactive Block Kit actions — handler for hermes:.* action IDs (buttons/selects), routes as synthetic MessageEvent (gateway/platforms/slack.py)
  • Message edit detectionmessage_changed events extract the inner edited message and re-process it instead of being ignored (gateway/platforms/slack.py)
  • Slash commands/hermes help, /hermes skills, /hermes status, /hermes config with Block Kit formatting, dispatch via SLASH_COMMANDS registry (gateway/platforms/slack_commands.py)

Shared utilities module (gateway/platforms/slack_utils.py)

  • SSRF protection (validate_slack_file_url, is_slack_hostname)
  • HTML detection for failed file downloads (looks_like_html_content)
  • Voice message MIME normalization (normalize_slack_voice_mimetype)
  • Markdown table to Slack code block conversion (convert_markdown_tables_to_slack)
  • Message update helpers (update_slack_message, SlackMessageRef)

Tests

  • Updated TestSlackThreadContext to test load_thread_context() instead of removed _fetch_thread_context()
  • Updated TestThreadEngagement to test ThreadParticipationCache instead of removed _bot_message_ts / _mentioned_threads sets
  • 88 Slack tests passing (16 approval + 69 main + 3 assistant thread)

How to Test

  1. Connect Hermes to a Slack workspace via Socket Mode
  2. Send a message in a channel with @hermes — verify mention gating responds correctly
  3. Reply in a thread where the bot has participated — verify implicit mention (no @ needed)
  4. Edit a message the bot responded to — verify it detects the edit
  5. Run /hermes status — verify Block Kit formatted response with connection state
  6. Run /hermes skills — verify skills list renders
  7. Run /hermes config — verify config summary renders
  8. Trigger a command that requires approval — verify buttons render and clicking Approve/Deny unblocks the command
  9. Test per-channel config by adding a channels block to gateway.slack in config.yaml

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform:

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

- Per-channel config (requireMention, allowBots, users, threadHistoryLimit)
- check_mention_gate() replaces inline conditionals — pure function, testable
- ThreadParticipationCache replaces _bot_message_ts/_mentioned_threads sets — TTL, LRU, async-safe
- load_thread_context() replaces _fetch_thread_context() — structured, paginated, preserves bot messages
- Connection health monitoring (SlackConnectionState, probe, stale socket detection)
- Block Kit rendering: send() wraps messages in section blocks via _content_to_blocks()
- Interactive Block Kit actions for hermes:.* buttons/selects
- Message edit detection (message_changed events)
- /hermes slash commands: help, skills, status, config
- Per-channel user authorization (is_user_allowed_in_channel)
- OAuth scope validation (fetch_slack_scopes, validate_slack_scopes)
- Shared utilities module: SSRF protection, table conversion, message update helpers
@teknium1

teknium1 commented Apr 9, 2026

Copy link
Copy Markdown
Contributor

Merged via PR #6809 as part of a consolidated Slack adapter improvement. Your contribution was superseded by the consolidated salvage. Your authorship is preserved in git history. Thank you @bennyhodl for your work on this!

@teknium1 teknium1 closed this Apr 9, 2026
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