

























@@ -27,6 +27,7 @@ import {
2727createSlackSessionStoreFixture,
2828createSlackTestAccount,
2929} from "./prepare.test-helpers.js";
30+import { clearSlackSubteamMentionCacheForTest } from "./subteam-mentions.js";
30313132const enqueueSystemEventMock = vi.hoisted(() => vi.fn());
3233@@ -49,6 +50,7 @@ describe("slack prepareSlackMessage inbound contract", () => {
4950resetSlackThreadStarterCacheForTest();
5051clearSlackThreadParticipationCache();
5152clearSlackAllowFromCacheForTest();
53+clearSlackSubteamMentionCacheForTest();
5254enqueueSystemEventMock.mockClear();
5355});
5456@@ -1183,6 +1185,95 @@ describe("slack prepareSlackMessage inbound contract", () => {
11831185expect(new Set([root!.ctxPayload.SessionKey, followUp!.ctxPayload.SessionKey]).size).toBe(1);
11841186});
118511871188+it("treats Slack user-group mentions as explicit mentions when the bot is a member", async () => {
1189+const usergroupsUsersList = vi.fn().mockResolvedValue({
1190+ok: true,
1191+users: ["U_OTHER", "B1"],
1192+});
1193+const slackCtx = createInboundSlackCtx({
1194+cfg: {
1195+channels: {
1196+slack: {
1197+enabled: true,
1198+groupPolicy: "open",
1199+channels: { C0AGENTS: { requireMention: true } },
1200+},
1201+},
1202+} as OpenClawConfig,
1203+appClient: {
1204+usergroups: { users: { list: usergroupsUsersList } },
1205+} as unknown as App["client"],
1206+defaultRequireMention: true,
1207+});
1208+slackCtx.resolveChannelName = async () => ({ name: "agents", type: "channel" });
1209+slackCtx.resolveUserName = async () => ({ name: "Bek" });
1210+1211+const prepared = await prepareSlackMessage({
1212+ctx: slackCtx,
1213+account: createSlackAccount(),
1214+message: {
1215+type: "message",
1216+channel: "C0AGENTS",
1217+channel_type: "channel",
1218+user: "U_BEK",
1219+text: "<!subteam^S0AGENTS|agents> triage this",
1220+ts: "1777244692.409919",
1221+} as SlackMessageEvent,
1222+opts: { source: "message" },
1223+});
1224+1225+expect(usergroupsUsersList).toHaveBeenCalledWith({
1226+usergroup: "S0AGENTS",
1227+team_id: "T1",
1228+});
1229+expect(prepared).toBeTruthy();
1230+expect(prepared!.ctxPayload.WasMentioned).toBe(true);
1231+});
1232+1233+it("drops Slack user-group mentions when the bot is not a member", async () => {
1234+const usergroupsUsersList = vi.fn().mockResolvedValue({
1235+ok: true,
1236+users: ["U_OTHER"],
1237+});
1238+const slackCtx = createInboundSlackCtx({
1239+cfg: {
1240+channels: {
1241+slack: {
1242+enabled: true,
1243+groupPolicy: "open",
1244+channels: { C0AGENTS: { requireMention: true } },
1245+},
1246+},
1247+} as OpenClawConfig,
1248+appClient: {
1249+usergroups: { users: { list: usergroupsUsersList } },
1250+} as unknown as App["client"],
1251+defaultRequireMention: true,
1252+});
1253+slackCtx.resolveChannelName = async () => ({ name: "agents", type: "channel" });
1254+slackCtx.resolveUserName = async () => ({ name: "Bek" });
1255+1256+const prepared = await prepareSlackMessage({
1257+ctx: slackCtx,
1258+account: createSlackAccount(),
1259+message: {
1260+type: "message",
1261+channel: "C0AGENTS",
1262+channel_type: "channel",
1263+user: "U_BEK",
1264+text: "<!subteam^S0AGENTS|agents> triage this",
1265+ts: "1777244692.409920",
1266+} as SlackMessageEvent,
1267+opts: { source: "message" },
1268+});
1269+1270+expect(usergroupsUsersList).toHaveBeenCalledWith({
1271+usergroup: "S0AGENTS",
1272+team_id: "T1",
1273+});
1274+expect(prepared).toBeNull();
1275+});
1276+11861277it("keeps a regex-mentioned Slack thread root and URL-only follow-up on one parent session", async () => {
11871278const { storePath } = storeFixture.makeTmpStorePath();
11881279const rootTs = "1777244692.409919";
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。