From 9be1e95dabf6e070ca554993dac9750129ee1bca Mon Sep 17 00:00:00 2001 From: hclsys Date: Sat, 11 Apr 2026 20:18:08 +0800 Subject: [PATCH] fix(matrix): trust m.mentions.user_ids as authoritative mention source MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit resolveMentions() required BOTH m.mentions.user_ids metadata AND a visible text or formatted_body mention for a user mention to register. When non-OpenClaw Matrix clients (Element, standalone bots via matrix-bot-sdk) send proper m.mentions metadata without duplicating the @-mention in the message body, the mention was silently ignored and requireMention: true dropped the message. Per MSC3952, m.mentions.user_ids is the authoritative mention source. The visible @-mention in the body is a display hint, not a prerequisite. Drop the conjunction so metadata-backed mentions are trusted on their own. The m.mentions.room check is left unchanged — visible @room text is still required alongside the metadata flag because @room mentions have different security implications (spam amplification). Fixes #64785 --- .../matrix/src/matrix/monitor/mentions.test.ts | 13 ++++++++----- extensions/matrix/src/matrix/monitor/mentions.ts | 9 ++++++--- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/extensions/matrix/src/matrix/monitor/mentions.test.ts b/extensions/matrix/src/matrix/monitor/mentions.test.ts index ca1f872d874..5553f131292 100644 --- a/extensions/matrix/src/matrix/monitor/mentions.test.ts +++ b/extensions/matrix/src/matrix/monitor/mentions.test.ts @@ -34,19 +34,22 @@ describe("resolveMentions", () => { expect(result.hasExplicitMention).toBe(true); }); - it("does not trust forged m.mentions.user_ids without a visible mention", () => { + it("detects mention via m.mentions.user_ids even without visible text mention (#64785)", () => { + // MSC3952: m.mentions.user_ids is the authoritative mention source. + // Non-OpenClaw Matrix clients (Element, standalone bots) may set + // m.mentions without including @bot in the visible message body. const result = resolveMentions({ content: { msgtype: "m.text", - body: "hello", + body: "please reply", "m.mentions": { user_ids: ["@bot:matrix.org"] }, }, userId, - text: "hello", + text: "please reply", mentionRegexes, }); - expect(result.wasMentioned).toBe(false); - expect(result.hasExplicitMention).toBe(false); + expect(result.wasMentioned).toBe(true); + expect(result.hasExplicitMention).toBe(true); }); it("detects room mention via visible @room text", () => { diff --git a/extensions/matrix/src/matrix/monitor/mentions.ts b/extensions/matrix/src/matrix/monitor/mentions.ts index e3c3556f602..dfba68d9cb0 100644 --- a/extensions/matrix/src/matrix/monitor/mentions.ts +++ b/extensions/matrix/src/matrix/monitor/mentions.ts @@ -163,10 +163,13 @@ export function resolveMentions(params: { mentionRegexes: params.mentionRegexes, }) : false; + // m.mentions.user_ids is the authoritative mention source per MSC3952. + // Previously this also required a visible text or formatted_body mention, + // which caused messages from non-OpenClaw clients that send proper + // m.mentions metadata without an @-mention in the body to be silently + // ignored when requireMention was enabled (#64785). const metadataBackedUserMention = Boolean( - params.userId && - mentionedUsers.has(params.userId) && - (mentionedInFormattedBody || textMentioned), + params.userId && mentionedUsers.has(params.userId), ); const metadataBackedRoomMention = Boolean(mentions?.room) && visibleRoomMention; const explicitMention =