Skip to content

feat(gateway): add Rocket.Chat platform adapter - #4637

Closed
meron1122 wants to merge 4 commits into
NousResearch:mainfrom
meron1122:feat/rocketchat-gateway
Closed

feat(gateway): add Rocket.Chat platform adapter#4637
meron1122 wants to merge 4 commits into
NousResearch:mainfrom
meron1122:feat/rocketchat-gateway

Conversation

@meron1122

Copy link
Copy Markdown

What

Adds a full Rocket.Chat gateway adapter (gateway/platforms/rocketchat.py) using the RC REST API v1 and DDP WebSocket (stream-room-messages / __my_messages__). No external Rocket.Chat library required — uses aiohttp which is already a Hermes dependency.

Changes

  • gateway/platforms/rocketchat.py — new adapter
  • gateway/config.pyPlatform.ROCKETCHAT enum + env-var config loading
  • gateway/run.py — adapter wiring, allowlist env vars
  • toolsets.pyhermes-rocketchat toolset + added to hermes-gateway
  • hermes_cli/tools_config.py — platform entry for setup wizard
  • tests/gateway/test_rocketchat.py — 37 tests (all passing)

Key behaviour

Auth — username+password (recommended, session token via POST /login) or PAT fallback. Session token is reused for DDP resume login so only one credential flow is needed.

Room type detection — uses GET /api/v1/rooms.info (works for channels, private groups, and DMs in a single request) with a per-room cache. Earlier heuristic of checking userId in eventName was unreliable across RC versions.

DM behaviour — emoji reactions (👀/✅/❌) and thread replies (tmid) are suppressed for DM rooms. Reactions can also be disabled globally with ROCKETCHAT_REACTIONS=false.

Markdown**bold***bold* (RC uses single asterisk), tilde replaced with U+223C TILDE OPERATOR so pairs like ~8.3°C … ~17.7°C are not rendered as strikethrough by RC's parser.

Deferred attachments — file-only upload messages are held in a per-room buffer (5 min TTL) and merged into the next text message from that room, enabling workflows like "here's a PDF [upload] → summarise it [text message]".

Environment variables

Variable Description
ROCKETCHAT_URL Server URL (required)
ROCKETCHAT_USERNAME Bot username (recommended)
ROCKETCHAT_PASSWORD Bot password (recommended)
ROCKETCHAT_TOKEN Personal access token (PAT fallback)
ROCKETCHAT_USER_ID User ID for PAT fallback
ROCKETCHAT_ALLOWED_USERS Comma-separated allowed user IDs
ROCKETCHAT_ALLOW_ALL_USERS Set true to allow all users
ROCKETCHAT_HOME_CHANNEL Room ID for cron/notification delivery
ROCKETCHAT_REQUIRE_MENTION Require @mention in channels (default: true)
ROCKETCHAT_FREE_RESPONSE_CHANNELS Room IDs where bot responds without @mention
ROCKETCHAT_REPLY_IN_THREAD Reply in thread for channel messages (default: false)
ROCKETCHAT_REACTIONS Enable emoji reactions on channels (default: true)

How to test

# Minimal setup
export ROCKETCHAT_URL=https://your-rc-instance.com
export ROCKETCHAT_USERNAME=hermesbot
export ROCKETCHAT_PASSWORD=yourpassword
export ROCKETCHAT_ALLOW_ALL_USERS=true

hermes gateway

Then DM the bot or @mention it in a channel. Upload a file without text, then send a follow-up message to verify deferred attachment works.

# Run tests
pytest tests/gateway/test_rocketchat.py -v

Platform tested on

  • macOS (darwin)
  • Self-hosted Rocket.Chat 6.x

Adds a full Rocket.Chat gateway adapter using the RC REST API v1 and
DDP WebSocket (stream-room-messages / __my_messages__).

Key design decisions and non-obvious behaviour:
- Auth supports username+password (session token via POST /login) and
  PAT fallback; session token is reused for DDP `resume` login.
- Room type is resolved via rooms.info (works for all types) and
  cached per room_id, avoiding the need to heuristically infer DM
  from the eventName string (unreliable across RC versions).
- Emoji reactions (👀/✅/❌) and thread replies (tmid) are suppressed
  for DM rooms unconditionally; reactions can also be disabled globally
  via ROCKETCHAT_REACTIONS=false.
- Tilde characters are replaced with U+223C (TILDE OPERATOR) so that
  pairs like ~8.3°C … ~17.7°C are not rendered as strikethrough.
- File-only upload messages are held in a per-room buffer (5 min TTL)
  and attached to the next text message from the same room, enabling
  "summarise the PDF I just sent" workflows.
meron1122 and others added 2 commits April 30, 2026 22:00
Move gateway/platforms/rocketchat.py into the new plugins/platforms/rocketchat/ plugin directory, following the pattern established by the teams and IRC platform plugins. Adds register(ctx), validate_config(), is_connected(), and interactive_setup() as required by the plugin contract. Updates tests to use the _plugin_adapter_loader pattern.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/plugins Plugin system and bundled plugins comp/gateway Gateway runner, session dispatch, delivery labels Apr 30, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Likely duplicate of #14869 — same Rocket.Chat adapter feature PR. Also related to feature request #3725.

1 similar comment
@alt-glitch

Copy link
Copy Markdown
Collaborator

Likely duplicate of #14869 — same Rocket.Chat adapter feature PR. Also related to feature request #3725.

@menardorama

Copy link
Copy Markdown

I tested this PR locally and identified 2 bugs that prevent the Rocket.Chat plugin from working properly:

Bug 1: plugins/platforms/rocketchat/__init__.py is empty

Problem: The plugin's __init__.py file is created empty during the migration to the plugin architecture. Without the register import, the plugin discovery system (discover_plugins()) cannot load the adapter.
Impact: Rocket.Chat doesn't appear in hermes status and the gateway cannot use the plugin.
Reproduction:

# After cloning and installing the PR
hermes status
# → Rocket.Chat is missing from the messaging platforms list
Fix:
# plugins/platforms/rocketchat/__init__.py
from .adapter import register
__all__ = ["register"]
---
Bug 2: hermes status doesn't call discover_plugins()
Problem: In hermes_cli/status.py, the section that lists plugin platforms doesn't call discover_plugins() before iterating over platform_registry.plugin_entries(). As a result, even with the fixed __init__.py, platform plugins don't appear.
Impact: The IRC, Rocket.Chat, and Teams plugins don't appear in hermes status until another command first calls discover_plugins().
Reproduction:
# Fresh shell session (no cache)
hermes status
# → IRC, Rocket.Chat, Microsoft Teams are missing from the list
Fix:
# hermes_cli/status.py (in show_status(), "Plugin-registered platforms" section)
# Plugin-registered platforms
try:
    from hermes_cli.plugins import discover_plugins
    discover_plugins()
    
    from gateway.platform_registry import platform_registry
    for entry in platform_registry.plugin_entries():
        configured = entry.check_fn()
        status_str = "configured" if configured else "not configured"
        label = entry.label
        print(f"  {label:<12}  {check_mark(configured)} {status_str} (plugin)")
except Exception:
    pass
---
Verification After Fixes
After applying both fixes:
hermes status
# Expected result:
◆ Messaging Platforms
  ...
  IRC           ✗ not configured (plugin)
  Rocket.Chat   ✗ not configured (plugin)
  Microsoft Teams  ✗ not configured (plugin)
The plugin is now correctly discovered and ready to be configured!

- Export register() from plugins/platforms/rocketchat/__init__.py so
  discover_plugins() can load the adapter (was empty, causing the plugin
  to be silently skipped)
- Call discover_plugins() in hermes_cli/status.py before iterating
  platform_registry.plugin_entries() so IRC, Rocket.Chat, and Teams
  appear in 'hermes status' on a fresh shell
@HearthCore

Copy link
Copy Markdown
Contributor

Hey @meron1122, thanks for your Rocket.Chat plugin work in this PR — your plugin-structure approach was a great reference. 🙏

@cyb0rgk1tty too — your PR #14869 with the core adapter code was the foundation we started from.

We built a more complete version that includes fixes for both bugs reported here by @menardorama (empty init.py and discover_plugins()), plus several enhancements from live operation:

Bugs fixed:

  • ✅ Proper init.py with from .adapter import register
  • ✅ Plugin auto-discovery handled correctly

Extra features:

  • ✅ TTS audio pipeline (voice messages to ffmpeg to MP3 for STT)
  • ✅ DDP reconnect with exponential backoff (2s-60s)
  • ✅ Bidirectional Hermes session title to RC room topic sync
  • ✅ Emoji reactions on channel messages
  • ✅ Slash command position-0 fix (mid-sentence false positives eliminated)
  • ✅ is_gateway_known_command() gate to skip RC routing for Hermes cmds
  • ✅ Deferred attachments (file-only uploads merge with next text msg)
  • ✅ AGENTS.md for AI assistant devs + full README.md

Our PR: #30463

Its a single-plugin addition with zero core Hermes changes. The feature set is more complete and ready for review/maintainer attention.

Happy to collaborate -- let us know what you think! 🔥

@engelgabriel

Copy link
Copy Markdown

@teknium1

Copy link
Copy Markdown
Contributor

Thanks for the substantial Rocket.Chat adapter work, including the plugin registration and test coverage.

This automated hermes-sweeper review is closing this as not_planned because it falls under the standing policy for third-party product integrations:

  • The PR adds a new in-tree integration at plugins/platforms/rocketchat/ (PR head 265a5ab327f5).
  • AGENTS.md:797-808 requires integrations for other products to ship as standalone plugin repositories, installed through ~/.hermes/plugins/ or a pip entry point, to avoid making their ongoing compatibility maintenance part of this repository.
  • The linked follow-up PR feat(plugins): add Rocket.Chat platform adapter as bundled plugin #30463 is also described as an in-tree Rocket.Chat plugin and therefore does not change the applicable packaging policy.

Please publish the adapter as a standalone plugin repository using the existing platform registry/plugin interface; it can then be shared through the Nous Research Discord #plugins-skills-and-skins channel.


Closed as not-planned per standing maintainer policy (in-tree-provider-integration). This is a design-direction decision, not a code-quality judgment — see the Contribution Rubric in AGENTS.md for what the project is looking for. If you believe this policy was misapplied to your change, comment here and a maintainer will take a look.

@teknium1 teknium1 closed this Jul 12, 2026
@teknium1 teknium1 added the sweeper:not-planned Sweeper: closed per standing maintainer policy (design direction) label Jul 12, 2026
@meron1122

Copy link
Copy Markdown
Author

I published plugin powerup with amazing features from @HearthCore and a few more. Feel free to use and contribute
https://github.com/HalfbitStudio/hermes-plugin-rocketchat

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

Labels

comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have sweeper:not-planned Sweeper: closed per standing maintainer policy (design direction) type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants