import { describe, expect, it } from "vitest"; import { hasMentionToken, inferHandoffTargetBotId, inferHandoffTargetName, resolveGroupTargetBotIds, } from "./group-mentions.js"; const members = [ { id: "a", name: "BotA" }, { id: "b", name: "BotB" }, { id: "c", name: "Writer" }, ]; describe("hasMentionToken", () => { it("requires a boundary after the complete member name", () => { expect(hasMentionToken("Ask @Ann to review", "Ann")).toBe(true); expect(hasMentionToken("Ask @Ann, then continue", "Ann")).toBe(true); expect(hasMentionToken("Ask @Anna to review", "Ann")).toBe(false); expect(hasMentionToken("name@Ann", "Ann")).toBe(false); expect(hasMentionToken("contact@everyone", "everyone")).toBe(false); }); it("supports multi-word and Unicode member names", () => { expect(hasMentionToken("Ask @Research Writer and @Éditeur", "Research Writer")).toBe(true); expect(hasMentionToken("Ask @Research Writer and @Éditeur", "Éditeur")).toBe(true); }); }); describe("resolveGroupTargetBotIds", () => { it("returns mentioned bots from text", () => { expect( resolveGroupTargetBotIds({ text: "@BotA gather sources. @BotB summarize.", members, }), ).toEqual(["a", "b"]); }); it("returns all members for @everyone", () => { expect( resolveGroupTargetBotIds({ text: "@everyone please review", members, }), ).toEqual(["a", "b", "c"]); }); it("merges explicit mentions", () => { expect( resolveGroupTargetBotIds({ text: "hello", members, explicitMentions: ["b"], }), ).toEqual(["b"]); }); it("matches multi-word and Unicode names without prefix collisions", () => { const namedMembers = [ { id: "research", name: "Research Writer" }, { id: "edit", name: "Éditeur" }, { id: "ann", name: "Ann" }, { id: "anna", name: "Anna" }, ]; expect( resolveGroupTargetBotIds({ text: "@Research Writer compare this with @Éditeur and @Anna.", members: namedMembers, }), ).toEqual(["research", "edit", "anna"]); }); it("ignores explicit mentions for bots that are not group members", () => { expect( resolveGroupTargetBotIds({ text: "hello", members, explicitMentions: ["b", "outsider"], }), ).toEqual(["b"]); }); it("picks the first member when unmentioned", () => { expect( resolveGroupTargetBotIds({ text: "hello team", members, }), ).toEqual(["a"]); }); it("lets the lead answer when unmentioned, but not when someone is addressed", () => { expect(resolveGroupTargetBotIds({ text: "hello team", members, defaultBotId: "c" })).toEqual([ "c", ]); expect( resolveGroupTargetBotIds({ text: "@BotB take this", members, defaultBotId: "c" }), ).toEqual(["b"]); }); it("falls back to the first member when the lead is not a member", () => { expect(resolveGroupTargetBotIds({ text: "hello team", members, defaultBotId: "gone" })).toEqual( ["a"], ); }); }); describe("inferHandoffTargetName", () => { it("picks Writer when BotA is also mentioned", () => { expect(inferHandoffTargetName("@BotA hand this to Writer for the draft")).toBe("Writer"); }); }); describe("inferHandoffTargetBotId", () => { it("recognizes hand this to Writer", () => { expect(inferHandoffTargetBotId("hand this to Writer for the draft", members)).toBe("c"); }); it("recognizes @Writer take the draft", () => { expect(inferHandoffTargetBotId("@Writer take the draft", members)).toBe("c"); }); it("resolves Writer from mixed mention prompt", () => { expect(inferHandoffTargetBotId("@BotA hand this to Writer for the draft", members)).toBe("c"); }); it("resolves multi-word handoff targets", () => { expect( inferHandoffTargetBotId("hand this to Research Writer for the draft", [ ...members, { id: "research", name: "Research Writer" }, ]), ).toBe("research"); }); });