feat(gateway): add Rocket.Chat platform adapter - #14869
Conversation
Connects Hermes to self-hosted Rocket.Chat (tested against 8.2) via the REST API (v1) for outbound writes and the Realtime (DDP) WebSocket for inbound messages. Single subscription to stream-room-messages on the __my_messages__ virtual room id covers every channel/DM/group the bot is a member of — no per-room enumeration required. Authentication uses a Personal Access Token (generate with "Ignore Two Factor Authentication" checked), which doubles as the DDP resume token. No new Python dependency: the adapter runs on aiohttp, already a core dep for the Mattermost / HomeAssistant / SMS adapters. Feature parity with the Mattermost adapter: - Send / edit / delete messages (chat.postMessage, chat.update) - Threaded replies via tmid (ROCKETCHAT_REPLY_MODE=thread) - File upload via the two-step rooms.media + rooms.mediaConfirm flow (replaces the deprecated rooms.upload endpoint) - Inbound file attachment download + cache into media_urls/media_types - Typing indicator via DDP stream-notify-room method - Mention gating with ROCKETCHAT_REQUIRE_MENTION and ROCKETCHAT_FREE_RESPONSE_CHANNELS; authoritative mentions[] array plus a text-scan fallback for edits - DM vs channel vs group type detection (t: d/c/p/l) - System-message filtering (skips messages with a non-empty t field) - Self-message filtering (skips msgs where u._id == bot_user_id) - Per-room ephemeral channel prompts via config.extra.channel_prompts - MessageDeduplicator-backed dedup on Rocket.Chat _id - Exponential-backoff reconnect (2s -> 60s with jitter); re-login and re-subscribe on every reconnect because DDP subs do not resume Full 16-point ADDING_A_PLATFORM.md wire-up: - Platform.ROCKETCHAT enum entry + env-override loading in config.py - Adapter factory branch + auth allowlist maps in run.py - PLATFORM_HINTS entry so the agent knows it is on Rocket.Chat - hermes-rocketchat toolset + include in hermes-gateway composite - Cron delivery platform_map + HOME_CHANNEL env var map - send_message_tool _send_rocketchat() standalone helper + routing - hermes_cli PLATFORMS registry, status display, gateway setup wizard - cronjob_tools deliver schema description Env var contract (ROCKETCHAT_URL, _TOKEN, _USER_ID, _ALLOWED_USERS, _ALLOW_ALL_USERS, _HOME_CHANNEL, _HOME_CHANNEL_NAME, _REQUIRE_MENTION, _FREE_RESPONSE_CHANNELS, _REPLY_MODE) mirrors the Mattermost shape so profile operators can map existing setup patterns directly. Tests: 46 new tests in tests/gateway/test_rocketchat.py covering config loading, format/truncate, send (with mocked aiohttp), DDP message parsing, dedup, mention behavior, threading, media type detection, and DDP framing (ping/pong, ready, stream-room-messages dispatch). Full pytest run shows no regressions against upstream main. Docs: new website/docs/user-guide/messaging/rocketchat.md setup guide, plus env-var reference table entries and messaging-index updates (platform capabilities table, mermaid diagram, next-steps list). Verified live against a self-hosted Rocket.Chat 8.2 workspace: REST auth, DDP subscribe, inbound DM parse, outbound chat.postMessage, and threaded replies all confirmed end-to-end with a real LLM roundtrip.
cb7ba94 to
368ebe0
Compare
Rocket.Chat 6.x replaced the legacy ``<rid>/typing`` DDP method call with ``<rid>/user-activity``, which takes an activity list (``["typing"]`` / ``["recording"]`` / ``["uploading"]`` / ``[]`` to clear). The server still silently accepts calls to the old ``/typing`` stream — returns ``msg: "result"`` with no error — but modern clients (Rocket.Chat 6.x+, confirmed against 8.2) no longer subscribe to it, so the "is typing…" indicator never rendered on the other side. Switch ``send_typing`` to emit ``[<rid>/user-activity, username, ["typing"]]`` and implement ``stop_typing`` to emit an empty activity list, matching the current Rocket.Chat client behavior. Verified live against a self-hosted Rocket.Chat 8.2 instance by inspecting the server's DDP responses to both variants. Existing tests still pass unchanged.
368ebe0 to
475777f
Compare
|
Hey @cyb0rgk1tty, thanks a lot for your work on the Rocket.Chat adapter — your PR #14869 was the foundation we built on. 🙏 We refactored your approach into the modern plugin format ( Key additions:
Our PR: #30463 Would love your thoughts on the approach! Happy to collaborate further. 🔥 Also tagging @meron1122 since your PR #4637 was a valuable reference for the plugin structure. |
|
Thanks for the substantial Rocket.Chat adapter work. Automated hermes-sweeper review found that this change matches the standing
This is an automated hermes-sweeper review. Closed as not-planned per standing maintainer policy ( |
|
I published plugin powerup with amazing features from @HearthCore and a few more. Feel free to use and contribute |
Summary
Adds a Rocket.Chat adapter so Hermes can chat from self-hosted Rocket.Chat alongside the existing platforms. Full parity with the Mattermost adapter: REST (v1) for outbound writes, DDP WebSocket for inbound receive, PAT auth, threaded replies via
tmid, file upload via the two-steprooms.mediaflow, mention gating, DM/channel/group detection, and system-message / self-message filtering.No new Python dependency — the adapter is built on
aiohttp, which is already required by the Mattermost / HomeAssistant / SMS adapters.Motivation
Rocket.Chat is a common self-hosted choice alongside Mattermost and Matrix. Users who run both wanted a single Hermes profile model across platforms.
What's in the diff
gateway/platforms/rocketchat.py(~560 lines) withRocketchatAdapter(BasePlatformAdapter).ADDING_A_PLATFORM.mdchecklist:Platform.ROCKETCHATenum +_apply_env_overrides()block ingateway/config.pyplatform_env_map/platform_allow_all_mapentries ingateway/run.pyPLATFORM_HINTSentry inagent/prompt_builder.py(so the agent knows Markdown + threads +MEDIA:hints apply)hermes-rocketchattoolset + inclusion inhermes-gatewaycomposite (toolsets.py)platform_map+_HOME_TARGET_ENV_VARSentry (cron/scheduler.py)_send_rocketchat()+platform_map+ dispatch intools/send_message_tool.pydeliverschema description bump intools/cronjob_tools.pyPLATFORMSregistry entry inhermes_cli/platforms.py, status display row inhermes_cli/status.py, full wizard entry inhermes_cli/gateway.pytests/gateway/test_rocketchat.py— 46 tests mirroringtest_mattermost.pycoverage (config loading, format/truncate, send with mocked aiohttp, DDP frame dispatch including ping/pong + ready + stream-room-messages, dedup, mention gating, threading, media-type MIME propagation, requirements check).website/docs/user-guide/messaging/rocketchat.mdsetup guide, plus table/diagram/next-steps updates inmessaging/index.mdand entries inreference/environment-variables.md.Env var contract
Mirrors the Mattermost env shape so existing profile tooling maps directly.
Test plan
pytest tests/gateway/test_rocketchat.py -q→ 46 passedpytest tests/ -q→ no new failures (the existing dingtalk/matrix/agent_cache failures onmainare pre-existing and unchanged)hermes gateway setuplists Rocket.Chat in the wizard with the correct prompts/api/v1/meauthenticationstream-room-messages:__my_messages__subscriptionchat.postMessagewithtmid(threaded reply visible in client)Notes
__my_messages__virtual room id (covers every room the bot is a member of with one sub). DDP subscriptions don't resume across reconnect, so the adapter re-logs-in and re-subscribes on every reconnect.rooms.media+rooms.mediaConfirmis used for uploads (the olderrooms.uploadis deprecated in 6.x+).🤖 Generated with Claude Code