fix: enforce requireMention setting for Feishu group chats#384
fix: enforce requireMention setting for Feishu group chats#384yan-labs wants to merge 1 commit intoop7418:mainfrom
Conversation
|
@yan-labs is attempting to deploy a commit to the op7418's projects Team on Vercel. A member of the Team first needs to authorize it. |
The `bridge_feishu_require_mention` setting existed in the config UI and was loaded from the database, but was never actually checked in the message handling pipeline. Group chat messages were always processed regardless of whether the bot was @mentioned. Changes: - Fetch bot identity (open_id) on plugin startup via getBotInfo() - Check `message.mentions` against botOpenId when requireMention is enabled and the message comes from a group chat (chatId starts with 'oc_') - Strip the @bot mention placeholder from message text so the LLM receives clean input - Return null (skip message) when requireMention is true and the bot is not mentioned
eb45ee5 to
d6b959a
Compare
JiwaniZakir
left a comment
There was a problem hiding this comment.
The race window in index.ts between gateway.start() and the completion of resolveBotIdentity() is a silent data-loss risk: any group messages arriving during that window will have this.botOpenId === '', causing findBotMention to return undefined, and the requireMention check in parseInboundMessage will then drop them unconditionally. The comment acknowledges the dynamic read but frames it as a feature rather than a hazard. A safer approach would be to buffer or re-queue messages that arrive before botOpenId is set, or to queue messages only after identity resolution completes.
The isGroupChat heuristic in inbound.ts — chatId.startsWith('oc_') — is an undocumented Feishu internal convention. If Feishu introduces additional group chat ID prefixes or changes this scheme, mention filtering silently breaks for those chats with no indication at the call site. A named constant or a comment linking to Feishu's API docs would make this less fragile.
In resolveBotIdentity, failed retries log a console.warn per attempt but the final console.error on total failure doesn't surface in any structured way — if an operator has requireMention: true and bot identity never resolves, the plugin initializes without error, silently discarding all group messages. Worth considering whether this condition should throw or set a flag that parseInboundMessage can distinguish from "bot identity known, not mentioned."
…esources, thread session Five community-reported Feishu bridge issues fixed together, audited against the current channels/feishu/* architecture (not the stale bridge/adapters/feishu-adapter.ts). #321 — thread session bleed: - inbound.ts: threadSession config was loaded but never checked. Thread address encoding now guarded by config.threadSession, so the setting actually works. #384 — requireMention group filtering: - inbound.ts: parse mentions[] and drop un-mentioned group messages when the setting is on. Strip the @bot placeholder from text so the LLM sees clean input. - index.ts: resolve bot open_id via getBotInfo() with retry after gateway.start(). - Fail-open during the bot identity startup gap — dropping every group message while identity resolves would look like a broken bot. Once identity resolves, the gate activates. If resolution fails entirely, logs clearly warn that requireMention is inactive. #282 — AskUserQuestion interactive card: - permission-broker.ts: remove blanket deny blacklist. Build ask:{requestId}:{idx} card with option buttons on channels that support them; store the questions payload in the suggestions field so the callback can echo them back. - handleAskUserQuestionCallback: resolves with updatedInput = { questions, answers } matching the native tool's expected shape. - QQ/Weixin (no button support): deny with clear reason rather than falling back to Allow/Deny, which would execute the tool with empty answers and produce "The user did not provide any answers." Caller can retry as plain text. - full_access auto-approve still skips AskUserQuestion — the user's choice carries semantic meaning beyond permission consent. - outbound.ts: indigo "Question" card header for ask: callbacks. - bridge-manager.ts: route ask: callbacks before perm: callbacks, skip the "Permission response recorded" confirmation (the model's reply is the answer). #291 — file/image/audio/video support: - New resource-downloader.ts: downloads via im.messageResource.get with 20MB limit, 2-retry exponential backoff, permanent-error detection (not-found / permission → don't retry). - inbound.ts: extract resource metadata (file_key, type, caption) for non-text message types into PendingResource[]. New parseMessageWithResources exposes both the base message and pending downloads to the caller. - index.ts: downloadAndEnqueue runs the downloads async so the gateway handler doesn't block long uploads; partial failures still enqueue with the text we have. - bridge-manager.ts: type-aware fallback prompt for attachment-only turns — replaces hardcoded "Describe this image" with per-type prompts (image/audio/ video/mixed) so non-image attachments don't mislead the model. #266 — outbound delivery reliability: - outbound.ts: sendMessage wrapped with exponential-backoff retry (2 retries). isTransientError() skips 4xx permanent errors (invalid app_id, missing scope, etc.) and retries on timeouts/network/5xx/rate-limit. Docs: - issue-tracker.md: update B-012 (multi-adapter) to "需重新诊断" based on code audit finding no obvious isolation break. Add B-017 tracking Feishu WSClient stability cluster (#323 #288 #199 #149 #148) that needs user logs. All 953 unit tests pass. Typecheck clean. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Problem
The
bridge_feishu_require_mentionsetting exists in the config UI and is loaded from the database, but it was never actually checked in the message handling pipeline. This means the bot responds to all messages in group chats, even when "Require @mention" is enabled.The Discord adapter correctly implements this check, but the Feishu adapter was missing the equivalent logic.
Changes
src/lib/channels/feishu/inbound.tsisBotMentioned()helper that checksmessage.mentionsarray for the bot'sopen_idconfig.requireMentionistrueand the message is from a group chat (oc_prefix), skip messages where the bot is not @mentioned@botmention placeholder (e.g.@_user_1) from message text so the LLM receives clean inputsrc/lib/channels/feishu/index.tsgetBotInfo()after gateway starts, storingbotOpenIdbotOpenIdtoparseInboundMessage()for mention detectionHow it works
Feishu includes a
mentionsarray inim.message.receive_v1events:{ "message": { "mentions": [ { "key": "@_user_1", "id": { "open_id": "ou_xxx" }, "name": "MyBot" } ] } }The fix checks this array against the bot's
open_id(fetched at startup) whenrequireMentionis enabled.Test plan
@botplaceholder should be stripped from the input