fix(issues): normalize HTML entities in @mention tokens before agent lookup (#1255)

Rich-text comments store entities like   after @names; strip them before matching agents so issue_comment_mentioned and wake injection work.

Made-with: Cursor
This commit is contained in:
Paperclip Dev 2026-03-20 16:38:55 +00:00
parent dfdd3784b9
commit 47449152ac
2 changed files with 35 additions and 1 deletions

View file

@ -0,0 +1,24 @@
import { describe, expect, it } from "vitest";
import { normalizeAgentMentionToken } from "../services/issues.ts";
describe("normalizeAgentMentionToken", () => {
it("strips hex numeric entities such as space ( )", () => {
expect(normalizeAgentMentionToken("Baba ")).toBe("Baba");
});
it("strips decimal numeric entities", () => {
expect(normalizeAgentMentionToken("Baba ")).toBe("Baba");
});
it("strips common named entities", () => {
expect(normalizeAgentMentionToken("Baba ")).toBe("Baba");
});
it("returns plain names unchanged", () => {
expect(normalizeAgentMentionToken("Baba")).toBe("Baba");
});
it("trims after stripping entities", () => {
expect(normalizeAgentMentionToken("Baba  ")).toBe("Baba");
});
});

View file

@ -196,6 +196,13 @@ function unreadForUserCondition(companyId: string, userId: string) {
`;
}
const HTML_ENTITY_IN_MENTION = /&#x[0-9a-fA-F]+;|&#[0-9]+;|&[a-z]+;/gi;
/** Strips common HTML entities from a raw @mention capture so UI-encoded bodies still match agent names. */
export function normalizeAgentMentionToken(raw: string): string {
return raw.replace(HTML_ENTITY_IN_MENTION, "").trim();
}
export function deriveIssueUserContext(
issue: IssueUserContextInput,
userId: string,
@ -1446,7 +1453,10 @@ export function issueService(db: Db) {
const re = /\B@([^\s@,!?.]+)/g;
const tokens = new Set<string>();
let m: RegExpExecArray | null;
while ((m = re.exec(body)) !== null) tokens.add(m[1].toLowerCase());
while ((m = re.exec(body)) !== null) {
const normalized = normalizeAgentMentionToken(m[1]);
if (normalized) tokens.add(normalized.toLowerCase());
}
if (tokens.size === 0) return [];
const rows = await db.select({ id: agents.id, name: agents.name })
.from(agents).where(eq(agents.companyId, companyId));