























@@ -0,0 +1,221 @@
1+import { beforeEach, describe, expect, it, vi } from "vitest";
2+3+// Hoisted mocks used across tests so vi.mock factories can reference them.
4+const { resolvePolicyMock, buildContextMock } = vi.hoisted(() => ({
5+resolvePolicyMock: vi.fn(),
6+buildContextMock: vi.fn(),
7+}));
8+9+vi.mock("../../inbound-policy.js", async (importOriginal) => {
10+const actual = await importOriginal<typeof import("../../inbound-policy.js")>();
11+return {
12+ ...actual,
13+resolveWhatsAppCommandAuthorized: async () => true,
14+resolveWhatsAppInboundPolicy: resolvePolicyMock,
15+};
16+});
17+18+vi.mock("./inbound-dispatch.js", async (importOriginal) => {
19+const actual = await importOriginal<typeof import("./inbound-dispatch.js")>();
20+return {
21+ ...actual,
22+buildWhatsAppInboundContext: buildContextMock,
23+dispatchWhatsAppBufferedReply: async () => ({
24+queuedFinal: false,
25+counts: { tool: 0, block: 0, final: 0 },
26+}),
27+resolveWhatsAppDmRouteTarget: () => null,
28+resolveWhatsAppResponsePrefix: () => undefined,
29+updateWhatsAppMainLastRoute: () => {},
30+};
31+});
32+33+vi.mock("../../identity.js", async (importOriginal) => {
34+const actual = await importOriginal<typeof import("../../identity.js")>();
35+return {
36+ ...actual,
37+getPrimaryIdentityId: () => null,
38+getSelfIdentity: () => ({ e164: "+15550001111" }),
39+getSenderIdentity: () => ({ name: "Alice", e164: "+15550002222" }),
40+};
41+});
42+43+vi.mock("../../reconnect.js", async (importOriginal) => {
44+const actual = await importOriginal<typeof import("../../reconnect.js")>();
45+return { ...actual, newConnectionId: () => "test-conn-id" };
46+});
47+48+vi.mock("../../session.js", async (importOriginal) => {
49+const actual = await importOriginal<typeof import("../../session.js")>();
50+return { ...actual, formatError: (e: unknown) => String(e) };
51+});
52+53+vi.mock("../deliver-reply.js", async (importOriginal) => {
54+const actual = await importOriginal<typeof import("../deliver-reply.js")>();
55+return { ...actual, deliverWebReply: async () => {} };
56+});
57+58+vi.mock("../loggers.js", async (importOriginal) => {
59+const actual = await importOriginal<typeof import("../loggers.js")>();
60+return {
61+ ...actual,
62+whatsappInboundLog: { info: () => {}, debug: () => {} },
63+};
64+});
65+66+vi.mock("./ack-reaction.js", async (importOriginal) => {
67+const actual = await importOriginal<typeof import("./ack-reaction.js")>();
68+return { ...actual, maybeSendAckReaction: async () => {} };
69+});
70+71+vi.mock("./inbound-context.js", async (importOriginal) => {
72+const actual = await importOriginal<typeof import("./inbound-context.js")>();
73+return {
74+ ...actual,
75+resolveVisibleWhatsAppGroupHistory: () => [],
76+resolveVisibleWhatsAppReplyContext: () => null,
77+};
78+});
79+80+vi.mock("./last-route.js", async (importOriginal) => {
81+const actual = await importOriginal<typeof import("./last-route.js")>();
82+return {
83+ ...actual,
84+trackBackgroundTask: () => {},
85+updateLastRouteInBackground: () => {},
86+};
87+});
88+89+vi.mock("./message-line.js", async (importOriginal) => {
90+const actual = await importOriginal<typeof import("./message-line.js")>();
91+return { ...actual, buildInboundLine: () => "hi" };
92+});
93+94+vi.mock("./runtime-api.js", async (importOriginal) => {
95+const actual = await importOriginal<typeof import("./runtime-api.js")>();
96+return {
97+ ...actual,
98+buildHistoryContextFromEntries: () => "hi",
99+createChannelReplyPipeline: () => ({ onModelSelected: () => {}, responsePrefix: undefined }),
100+formatInboundEnvelope: () => "hi",
101+logVerbose: () => {},
102+normalizeE164: (v: string) => v,
103+recordSessionMetaFromInbound: async () => {},
104+resolveChannelContextVisibilityMode: () => "off",
105+resolveInboundSessionEnvelopeContext: () => ({
106+storePath: "/tmp",
107+envelopeOptions: {},
108+previousTimestamp: undefined,
109+}),
110+resolvePinnedMainDmOwnerFromAllowlist: () => null,
111+shouldComputeCommandAuthorized: () => false,
112+shouldLogVerbose: () => false,
113+};
114+});
115+116+import { processMessage } from "./process-message.js";
117+118+// ---------------------------------------------------------------------------
119+// Helpers
120+// ---------------------------------------------------------------------------
121+122+function makeAccount(groups: Record<string, { systemPrompt?: string }> = {}): {
123+accountId: string;
124+authDir: string;
125+groups: Record<string, { systemPrompt?: string }>;
126+} {
127+return { accountId: "default", authDir: "/tmp/wa-test-auth", groups };
128+}
129+130+function makePolicy(account: ReturnType<typeof makeAccount>) {
131+return {
132+ account,
133+dmPolicy: "pairing",
134+groupPolicy: "allowlist",
135+configuredAllowFrom: [],
136+dmAllowFrom: [],
137+groupAllowFrom: [],
138+isSelfChat: false,
139+providerMissingFallbackApplied: false,
140+shouldReadStorePairingApprovals: true,
141+isSamePhone: () => false,
142+isDmSenderAllowed: () => false,
143+isGroupSenderAllowed: () => false,
144+resolveConversationGroupPolicy: () => "allowlist",
145+resolveConversationRequireMention: () => false,
146+};
147+}
148+149+const GROUP_JID = "123@g.us";
150+151+const baseMsg = {
152+id: "msg1",
153+from: GROUP_JID,
154+to: "+15550001111",
155+conversationId: GROUP_JID,
156+accountId: "default",
157+chatId: GROUP_JID,
158+chatType: "group" as const,
159+body: "hi",
160+sendComposing: async () => {},
161+reply: async () => {},
162+sendMedia: async () => {},
163+};
164+165+const baseRoute = {
166+agentId: "main",
167+channel: "whatsapp",
168+accountId: "default",
169+sessionKey: "agent:main:whatsapp:group:123@g.us",
170+mainSessionKey: "agent:main:whatsapp:group:123@g.us",
171+lastRoutePolicy: "main",
172+matchedBy: "default",
173+};
174+175+function callProcessMessage() {
176+return processMessage({
177+cfg: {} as never,
178+msg: baseMsg as never,
179+route: baseRoute as never,
180+groupHistoryKey: "whatsapp:default:group:123@g.us",
181+groupHistories: new Map(),
182+groupMemberNames: new Map(),
183+connectionId: "conn-1",
184+verbose: false,
185+maxMediaBytes: 1024,
186+replyResolver: (async () => undefined) as never,
187+replyLogger: { info: () => {}, warn: () => {}, error: () => {}, debug: () => {} } as never,
188+backgroundTasks: new Set(),
189+rememberSentText: () => {},
190+echoHas: () => false,
191+echoForget: () => {},
192+buildCombinedEchoKey: ({ sessionKey }) => sessionKey,
193+});
194+}
195+196+// ---------------------------------------------------------------------------
197+// Tests
198+// ---------------------------------------------------------------------------
199+200+describe("processMessage group system prompt wiring", () => {
201+beforeEach(() => {
202+buildContextMock.mockReset();
203+resolvePolicyMock.mockReset();
204+buildContextMock.mockImplementation(
205+(params: { groupSystemPrompt?: string; combinedBody?: string }) => ({
206+GroupSystemPrompt: params.groupSystemPrompt,
207+Body: params.combinedBody ?? "",
208+}),
209+);
210+});
211+212+it("resolves group systemPrompt from account config and passes it into buildWhatsAppInboundContext", async () => {
213+resolvePolicyMock.mockReturnValue(
214+makePolicy(makeAccount({ [GROUP_JID]: { systemPrompt: "from config" } })),
215+);
216+217+await callProcessMessage();
218+219+expect(buildContextMock.mock.calls[0][0].groupSystemPrompt).toBe("from config");
220+});
221+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。