hermes - 💡(How to fix) Fix Gateway mention gates can drop Feishu reply @mentions before hydration [3 pull requests]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Root Cause

Feishu is special because text content can contain placeholders such as @_user_1 while the identity mapping lives in mentions[].

Fix Action

Fixed

Code Example

{"text":"@_user_1"}

---

{
  "mentions": [
    {
      "key": "@_user_1",
      "name": "fy_bot",
      "id": "<bot open_id>",
      "id_type": "open_id"
    }
  ],
  "parent_id": "<parent message id>",
  "root_id": "<root message id>"
}

---

async def _handle_message_event_data(self, data):
    ...
    reason = self._admit(sender, message)
    if reason is not None:
        logger.debug("[Feishu] dropping inbound event: %s", reason)
        return
    await self._process_inbound_message(...)

---

if require_mention and not self._mentions_self(message):
    return "group_policy_rejected"

---

REST mentions string id: mentions_self=True,  admit_reason=None
WS standalone nested id: mentions_self=True,  admit_reason=None
WS reply with no mentions but content {"text":"@_user_1"}: mentions_self=False, admit_reason=group_policy_rejected
RAW_BUFFERClick to expand / collapse

Bug Description

AI-generated issue from a live debugging session. Please verify details against the current code before merging any fix.

Hermes' group-message admission gates can miss direct bot mentions when they rely only on the platform SDK's normalized mentions field before doing any platform-specific fallback/hydration.

This is a general gateway robustness problem across platforms: the admission decision (require_mention, multi-bot filtering, "mentioned bot only" behavior) should not depend on a single SDK-normalized mention representation when the raw platform event may contain equivalent mention information in another form.

A concrete Feishu/Lark case exposes this clearly:

  • In a Feishu group with FEISHU_REQUIRE_MENTION=true, a standalone/new message that @mentions the bot is admitted and processed.
  • A reply message that @mentions the bot can be received by the websocket adapter but silently dropped before the agent pipeline.
  • Fetching the same message via Feishu REST im/v1/messages/{message_id} shows a correct mentions[] entry for the bot, including the bot open_id.
  • The live websocket event path apparently does not provide message.mentions in the same shape for reply messages, so the pre-processing admission check misclassifies the message as not mentioning the bot.

Why this is probably not Feishu-only

This belongs to a broader class of bugs seen in bot gateways:

  • Discord mention detection has had to handle both message.mentions and raw content forms like <@ID> / <@!ID>.
  • Telegram/Signal-style group require_mention gates have similar edge cases around explicit mentions, multiple bots in one group, and command/mention parsing.
  • In general, platform SDKs may omit, normalize, or reshape mentions differently depending on message type, reply/thread context, bot/user entity type, or API surface.

The platform adapters should ideally have a layered mention detection strategy:

  1. SDK-normalized mentions, when present.
  2. Raw-content platform syntax fallback, when it contains enough identity information.
  3. Platform API hydration/fetch fallback when raw content only has opaque placeholders.

Feishu-specific details

Feishu is special because text content can contain placeholders such as @_user_1 while the identity mapping lives in mentions[].

For standalone @mentions, the websocket event usually provides a usable message.mentions payload, so Hermes works.

For reply messages, the observed failing event had content equivalent to:

{"text":"@_user_1"}

The REST message fetch for that same message returned a valid mention mapping similar to:

{
  "mentions": [
    {
      "key": "@_user_1",
      "name": "fy_bot",
      "id": "<bot open_id>",
      "id_type": "open_id"
    }
  ],
  "parent_id": "<parent message id>",
  "root_id": "<root message id>"
}

Because the raw Feishu text only has @_user_1 and not the actual bot open_id, a pure raw-content regex fallback is not enough for Feishu. The adapter needs to use REST hydration before rejecting ambiguous group messages.

Current Code Path / Suspected Root Cause

In gateway/platforms/feishu.py, inbound events are handled roughly as:

async def _handle_message_event_data(self, data):
    ...
    reason = self._admit(sender, message)
    if reason is not None:
        logger.debug("[Feishu] dropping inbound event: %s", reason)
        return
    await self._process_inbound_message(...)

_admit() enforces the group mention gate before _process_inbound_message() / _extract_message_content() has a chance to do any richer content processing:

if require_mention and not self._mentions_self(message):
    return "group_policy_rejected"

_mentions_self() ultimately relies on message.mentions (or normalization based on the same message.mentions). When message.mentions is absent/incomplete for a Feishu reply, the placeholder in raw content is normalized away and the message is rejected.

A minimal reproduction of the current behavior is:

REST mentions string id: mentions_self=True,  admit_reason=None
WS standalone nested id: mentions_self=True,  admit_reason=None
WS reply with no mentions but content {"text":"@_user_1"}: mentions_self=False, admit_reason=group_policy_rejected

Expected Behavior

If a user replies in a Feishu group and explicitly @mentions the bot, Hermes should process the message when group require_mention is enabled.

The adapter should not silently drop the event solely because the websocket SDK event lacks a usable message.mentions shape, especially when the REST message API can confirm the mention.

Actual Behavior

Hermes receives the raw Feishu websocket event and logs the raw message id/type, but no subsequent Inbound group message received / batch flush / agent pipeline log appears. The message is dropped during admission.

Suggested Fix Direction

For Feishu specifically:

  • When _admit() is about to reject a group message for require_mention failure, check whether the event is ambiguous and worth hydrating:
    • message.content contains a Feishu mention placeholder such as @_user_..., or
    • message has reply/thread fields such as parent_id, root_id, thread_id, upper_message_id.
  • Fetch the full message via im/v1/messages/{message_id} before rejecting.
  • Merge/copy the REST mentions[] onto the message or run _mentions_self() against the hydrated message representation.
  • Only reject if the hydrated representation still does not mention the bot.
  • Add an INFO/DEBUG log reason that includes enough non-secret context (message_id, chat_id, reject reason, whether hydration was attempted/succeeded) to debug future admission drops.

For the broader gateway pattern:

  • Consider a common adapter guideline/helper for mention admission:
    • first check SDK mentions,
    • then raw syntax,
    • then platform-specific hydration when raw syntax has opaque placeholders.
  • Avoid making irreversible admission decisions before platform-specific normalization/hydration has had a chance to recover mention identity.

Environment / Configuration

Observed with:

  • Feishu/Lark websocket integration
  • Group chat
  • FEISHU_REQUIRE_MENTION=true
  • FEISHU_GROUP_POLICY=open
  • Bot identity hydration working: /open-apis/bot/v3/info returns a bot open_id, and REST message mentions[] uses the same open_id.

No secrets or tenant-specific identifiers are included in this report.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - 💡(How to fix) Fix Gateway mention gates can drop Feishu reply @mentions before hydration [3 pull requests]