
























@@ -6,9 +6,9 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
66import type { OpenClawConfig } from "../config/config.js";
77import type { GroupKeyResolution } from "../config/sessions.js";
88import { channelRouteDedupeKey } from "../plugin-sdk/channel-route.js";
9-import { resetPluginRuntimeStateForTest } from "../plugins/runtime.js";
9+import { resetPluginRuntimeStateForTest, setActivePluginRegistry } from "../plugins/runtime.js";
10+import { createChannelTestPluginBase, createTestRegistry } from "../test-utils/channel-plugins.js";
1011import { createInboundDebouncer } from "./inbound-debounce.js";
11-import { installGroupRequireMentionTestPlugins } from "./inbound.group-require-mention-test-plugins.js";
1212import { resolveGroupRequireMention } from "./reply/groups.js";
1313import { finalizeInboundContext } from "./reply/inbound-context.js";
1414import {
@@ -26,6 +26,121 @@ import {
2626import { initSessionState } from "./reply/session.js";
2727import { applyTemplate, type MsgContext, type TemplateContext } from "./templating.js";
282829+type TestChannelGroupContext = {
30+cfg: OpenClawConfig;
31+groupId?: string | null;
32+groupChannel?: string | null;
33+groupSpace?: string | null;
34+accountId?: string | null;
35+};
36+37+function normalizeTestSlug(raw?: string | null): string {
38+return raw?.trim().replace(/^#/, "").toLowerCase() ?? "";
39+}
40+41+function resolveDiscordRequireMentionForTest(params: TestChannelGroupContext): boolean {
42+const discordCfg = params.cfg.channels?.discord as
43+| {
44+guilds?: Record<
45+string,
46+{
47+requireMention?: boolean;
48+slug?: string;
49+channels?: Record<string, { requireMention?: boolean }>;
50+}
51+>;
52+}
53+| undefined;
54+const guilds = discordCfg?.guilds;
55+if (!guilds) {
56+return true;
57+}
58+const space = params.groupSpace?.trim() ?? "";
59+const spaceSlug = normalizeTestSlug(space);
60+const guild =
61+(space ? guilds[space] : undefined) ??
62+(spaceSlug ? guilds[spaceSlug] : undefined) ??
63+Object.values(guilds).find((entry) => normalizeTestSlug(entry?.slug) === spaceSlug) ??
64+guilds["*"];
65+const channelSlug = normalizeTestSlug(params.groupChannel);
66+const channel =
67+(params.groupId ? guild?.channels?.[params.groupId] : undefined) ??
68+(channelSlug ? guild?.channels?.[channelSlug] : undefined) ??
69+(channelSlug ? guild?.channels?.[`#${channelSlug}`] : undefined);
70+return channel?.requireMention ?? guild?.requireMention ?? true;
71+}
72+73+function resolveSlackRequireMentionForTest(params: TestChannelGroupContext): boolean {
74+const slackCfg = params.cfg.channels?.slack as
75+| {
76+defaultAccount?: string;
77+channels?: Record<string, { requireMention?: boolean }>;
78+accounts?: Record<string, { channels?: Record<string, { requireMention?: boolean }> }>;
79+}
80+| undefined;
81+if (!slackCfg) {
82+return true;
83+}
84+const accountId = params.accountId ?? slackCfg.defaultAccount;
85+const channels =
86+(accountId ? slackCfg.accounts?.[accountId]?.channels : undefined) ?? slackCfg.channels;
87+if (!channels) {
88+return true;
89+}
90+const channelName = params.groupChannel?.trim().replace(/^#/, "");
91+const channelSlug = normalizeTestSlug(channelName);
92+const candidates = [
93+params.groupId?.trim(),
94+channelName ? `#${channelName}` : undefined,
95+channelName,
96+channelSlug,
97+"*",
98+];
99+for (const candidate of candidates) {
100+if (!candidate) {
101+continue;
102+}
103+const entry = channels[candidate];
104+if (typeof entry?.requireMention === "boolean") {
105+return entry.requireMention;
106+}
107+}
108+return true;
109+}
110+111+function installGroupRequireMentionTestPlugins() {
112+setActivePluginRegistry(
113+createTestRegistry([
114+{
115+pluginId: "discord",
116+plugin: {
117+ ...createChannelTestPluginBase({ id: "discord" }),
118+groups: { resolveRequireMention: resolveDiscordRequireMentionForTest },
119+},
120+source: "test",
121+},
122+{
123+pluginId: "slack",
124+plugin: {
125+ ...createChannelTestPluginBase({ id: "slack" }),
126+groups: { resolveRequireMention: resolveSlackRequireMentionForTest },
127+},
128+source: "test",
129+},
130+{
131+pluginId: "line",
132+plugin: createChannelTestPluginBase({ id: "line" }),
133+source: "test",
134+},
135+{
136+pluginId: "imessage",
137+plugin: createChannelTestPluginBase({ id: "imessage" }),
138+source: "test",
139+},
140+]),
141+);
142+}
143+29144describe("applyTemplate", () => {
30145it("renders primitive values", () => {
31146const ctx = { MessageSid: "sid", IsNewSession: "no" } as TemplateContext;
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。