fix(mentions): check mentionPatterns even when explicit mention is available

This commit is contained in:
HirokiKobayashi-R
2026-01-28 20:35:36 +09:00
committed by Ayaan Zaidi
parent fcc53bcf1b
commit 22b59d24ce
5 changed files with 26 additions and 10 deletions

View File

@@ -4,7 +4,7 @@ import { matchesMentionWithExplicit } from "./mentions.js";
describe("matchesMentionWithExplicit", () => {
const mentionRegexes = [/\bclawd\b/i];
it("prefers explicit mentions when other mentions are present", () => {
it("checks mentionPatterns even when explicit mention is available", () => {
const result = matchesMentionWithExplicit({
text: "@clawd hello",
mentionRegexes,
@@ -14,6 +14,19 @@ describe("matchesMentionWithExplicit", () => {
canResolveExplicit: true,
},
});
expect(result).toBe(true);
});
it("returns false when explicit is false and no regex match", () => {
const result = matchesMentionWithExplicit({
text: "<@999999> hello",
mentionRegexes,
explicit: {
hasAnyMention: true,
isExplicitlyMentioned: false,
canResolveExplicit: true,
},
});
expect(result).toBe(false);
});

View File

@@ -90,7 +90,9 @@ export function matchesMentionWithExplicit(params: {
const explicit = params.explicit?.isExplicitlyMentioned === true;
const explicitAvailable = params.explicit?.canResolveExplicit === true;
const hasAnyMention = params.explicit?.hasAnyMention === true;
if (hasAnyMention && explicitAvailable) return explicit;
if (hasAnyMention && explicitAvailable) {
return explicit || params.mentionRegexes.some((re) => re.test(cleaned));
}
if (!cleaned) return explicit;
return explicit || params.mentionRegexes.some((re) => re.test(cleaned));
}

View File

@@ -135,7 +135,7 @@ describe("discord tool result dispatch", () => {
expect(sendMock).toHaveBeenCalledTimes(1);
}, 20_000);
it("skips guild messages when another user is explicitly mentioned", async () => {
it("accepts guild messages when mentionPatterns match even if another user is mentioned", async () => {
const { createDiscordMessageHandler } = await import("./monitor.js");
const cfg = {
agents: {
@@ -211,8 +211,8 @@ describe("discord tool result dispatch", () => {
client,
);
expect(dispatchMock).not.toHaveBeenCalled();
expect(sendMock).not.toHaveBeenCalled();
expect(dispatchMock).toHaveBeenCalledTimes(1);
expect(sendMock).toHaveBeenCalledTimes(1);
}, 20_000);
it("accepts guild reply-to-bot messages as implicit mentions", async () => {

View File

@@ -392,7 +392,7 @@ describe("monitorSlackProvider tool results", () => {
expect(replyMock.mock.calls[0][0].WasMentioned).toBe(true);
});
it("skips channel messages when another user is explicitly mentioned", async () => {
it("accepts channel messages when mentionPatterns match even if another user is mentioned", async () => {
slackTestState.config = {
messages: {
responsePrefix: "PFX",
@@ -433,8 +433,8 @@ describe("monitorSlackProvider tool results", () => {
controller.abort();
await run;
expect(replyMock).not.toHaveBeenCalled();
expect(sendMock).not.toHaveBeenCalled();
expect(replyMock).toHaveBeenCalledTimes(1);
expect(replyMock.mock.calls[0][0].WasMentioned).toBe(true);
});
it("treats replies to bot threads as implicit mentions", async () => {

View File

@@ -212,7 +212,7 @@ describe("createTelegramBot", () => {
);
});
it("skips group messages when another user is explicitly mentioned", async () => {
it("accepts group messages when mentionPatterns match even if another user is mentioned", async () => {
onSpy.mockReset();
const replySpy = replyModule.__replySpy as unknown as ReturnType<typeof vi.fn>;
replySpy.mockReset();
@@ -249,7 +249,8 @@ describe("createTelegramBot", () => {
getFile: async () => ({ download: async () => new Uint8Array() }),
});
expect(replySpy).not.toHaveBeenCalled();
expect(replySpy).toHaveBeenCalledTimes(1);
expect(replySpy.mock.calls[0][0].WasMentioned).toBe(true);
});
it("keeps group envelope headers stable (sender identity is separate)", async () => {