mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 16:58:25 +00:00
perf(test): consolidate web auto-reply suites
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import type { WebInboundMsg } from "./types.js";
|
||||
import { isBotMentionedFromTargets, resolveMentionTargets } from "./mentions.js";
|
||||
@@ -52,4 +55,64 @@ describe("isBotMentionedFromTargets", () => {
|
||||
const targets = resolveMentionTargets(msg);
|
||||
expect(isBotMentionedFromTargets(msg, mentionCfg, targets)).toBe(true);
|
||||
});
|
||||
|
||||
it("ignores JID mentions in self-chat mode", () => {
|
||||
const cfg = { mentionRegexes: [/\bopenclaw\b/i], allowFrom: ["+999"] };
|
||||
const msg = makeMsg({
|
||||
body: "@owner ping",
|
||||
mentionedJids: ["999@s.whatsapp.net"],
|
||||
selfE164: "+999",
|
||||
selfJid: "999@s.whatsapp.net",
|
||||
});
|
||||
const targets = resolveMentionTargets(msg);
|
||||
expect(isBotMentionedFromTargets(msg, cfg, targets)).toBe(false);
|
||||
|
||||
const msgTextMention = makeMsg({
|
||||
body: "openclaw ping",
|
||||
selfE164: "+999",
|
||||
selfJid: "999@s.whatsapp.net",
|
||||
});
|
||||
const targetsText = resolveMentionTargets(msgTextMention);
|
||||
expect(isBotMentionedFromTargets(msgTextMention, cfg, targetsText)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolveMentionTargets with @lid mapping", () => {
|
||||
it("resolves mentionedJids via lid reverse mapping in authDir", async () => {
|
||||
const authDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-lid-mapping-"));
|
||||
try {
|
||||
await fs.writeFile(
|
||||
path.join(authDir, "lid-mapping-777_reverse.json"),
|
||||
JSON.stringify("+1777"),
|
||||
);
|
||||
const msg = makeMsg({
|
||||
body: "ping",
|
||||
mentionedJids: ["777@lid"],
|
||||
selfE164: "+15551234567",
|
||||
selfJid: "15551234567@s.whatsapp.net",
|
||||
});
|
||||
const targets = resolveMentionTargets(msg, authDir);
|
||||
expect(targets.normalizedMentions).toContain("+1777");
|
||||
} finally {
|
||||
await fs.rm(authDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("derives selfE164 from selfJid when selfJid is @lid and mapping exists", async () => {
|
||||
const authDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-lid-mapping-"));
|
||||
try {
|
||||
await fs.writeFile(
|
||||
path.join(authDir, "lid-mapping-777_reverse.json"),
|
||||
JSON.stringify("+1777"),
|
||||
);
|
||||
const msg = makeMsg({
|
||||
body: "ping",
|
||||
selfJid: "777@lid",
|
||||
});
|
||||
const targets = resolveMentionTargets(msg, authDir);
|
||||
expect(targets.selfE164).toBe("+1777");
|
||||
} finally {
|
||||
await fs.rm(authDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,23 +1,73 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
||||
import { resolveAgentRoute } from "../../../routing/resolve-route.js";
|
||||
import { buildMentionConfig } from "../mentions.js";
|
||||
import { applyGroupGating } from "./group-gating.js";
|
||||
|
||||
const baseConfig = {
|
||||
channels: {
|
||||
whatsapp: {
|
||||
groupPolicy: "open",
|
||||
groups: { "*": { requireMention: true } },
|
||||
let sessionDir: string | undefined;
|
||||
let sessionStorePath: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
sessionDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-group-gating-"));
|
||||
sessionStorePath = path.join(sessionDir, "sessions.json");
|
||||
await fs.writeFile(sessionStorePath, "{}");
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
if (sessionDir) {
|
||||
await fs.rm(sessionDir, { recursive: true, force: true });
|
||||
sessionDir = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
const makeConfig = (overrides: Record<string, unknown>) =>
|
||||
({
|
||||
channels: {
|
||||
whatsapp: {
|
||||
groupPolicy: "open",
|
||||
groups: { "*": { requireMention: true } },
|
||||
},
|
||||
},
|
||||
},
|
||||
session: { store: "/tmp/openclaw-sessions.json" },
|
||||
} as const;
|
||||
session: { store: sessionStorePath },
|
||||
...overrides,
|
||||
}) as unknown as ReturnType<typeof import("../../../config/config.js").loadConfig>;
|
||||
|
||||
function runGroupGating(params: {
|
||||
cfg: ReturnType<typeof import("../../../config/config.js").loadConfig>;
|
||||
msg: Record<string, unknown>;
|
||||
conversationId?: string;
|
||||
agentId?: string;
|
||||
}) {
|
||||
const groupHistories = new Map<string, unknown[]>();
|
||||
const conversationId = params.conversationId ?? "123@g.us";
|
||||
const agentId = params.agentId ?? "main";
|
||||
const sessionKey = `agent:${agentId}:whatsapp:group:${conversationId}`;
|
||||
const baseMentionConfig = buildMentionConfig(params.cfg, undefined);
|
||||
const result = applyGroupGating({
|
||||
cfg: params.cfg,
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
msg: params.msg as any,
|
||||
conversationId,
|
||||
groupHistoryKey: `whatsapp:default:group:${conversationId}`,
|
||||
agentId,
|
||||
sessionKey,
|
||||
baseMentionConfig,
|
||||
groupHistories,
|
||||
groupHistoryLimit: 10,
|
||||
groupMemberNames: new Map(),
|
||||
logVerbose: () => {},
|
||||
replyLogger: { debug: () => {} },
|
||||
});
|
||||
return { result, groupHistories };
|
||||
}
|
||||
|
||||
describe("applyGroupGating", () => {
|
||||
it("treats reply-to-bot as implicit mention", () => {
|
||||
const groupHistories = new Map();
|
||||
const result = applyGroupGating({
|
||||
cfg: baseConfig as unknown as ReturnType<
|
||||
typeof import("../../../config/config.js").loadConfig
|
||||
>,
|
||||
const cfg = makeConfig({});
|
||||
const { result } = runGroupGating({
|
||||
cfg,
|
||||
msg: {
|
||||
id: "m1",
|
||||
from: "123@g.us",
|
||||
@@ -39,18 +89,254 @@ describe("applyGroupGating", () => {
|
||||
reply: async () => {},
|
||||
sendMedia: async () => {},
|
||||
},
|
||||
conversationId: "123@g.us",
|
||||
groupHistoryKey: "whatsapp:default:group:123@g.us",
|
||||
agentId: "main",
|
||||
sessionKey: "agent:main:whatsapp:group:123@g.us",
|
||||
baseMentionConfig: { mentionRegexes: [] },
|
||||
groupHistories,
|
||||
groupHistoryLimit: 10,
|
||||
groupMemberNames: new Map(),
|
||||
logVerbose: () => {},
|
||||
replyLogger: { debug: () => {} },
|
||||
});
|
||||
|
||||
expect(result.shouldProcess).toBe(true);
|
||||
});
|
||||
|
||||
it("bypasses mention gating for owner /new in group chats", () => {
|
||||
const cfg = makeConfig({
|
||||
channels: {
|
||||
whatsapp: {
|
||||
allowFrom: ["+111"],
|
||||
groups: { "*": { requireMention: true } },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { result } = runGroupGating({
|
||||
cfg,
|
||||
msg: {
|
||||
id: "g-new",
|
||||
from: "123@g.us",
|
||||
conversationId: "123@g.us",
|
||||
chatId: "123@g.us",
|
||||
chatType: "group",
|
||||
to: "+2",
|
||||
body: "/new",
|
||||
senderE164: "+111",
|
||||
senderName: "Owner",
|
||||
selfE164: "+999",
|
||||
sendComposing: async () => {},
|
||||
reply: async () => {},
|
||||
sendMedia: async () => {},
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.shouldProcess).toBe(true);
|
||||
});
|
||||
|
||||
it("does not bypass mention gating for non-owner /new in group chats", () => {
|
||||
const cfg = makeConfig({
|
||||
channels: {
|
||||
whatsapp: {
|
||||
allowFrom: ["+999"],
|
||||
groups: { "*": { requireMention: true } },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { result, groupHistories } = runGroupGating({
|
||||
cfg,
|
||||
msg: {
|
||||
id: "g-new-unauth",
|
||||
from: "123@g.us",
|
||||
conversationId: "123@g.us",
|
||||
chatId: "123@g.us",
|
||||
chatType: "group",
|
||||
to: "+2",
|
||||
body: "/new",
|
||||
senderE164: "+111",
|
||||
senderName: "NotOwner",
|
||||
selfE164: "+999",
|
||||
sendComposing: async () => {},
|
||||
reply: async () => {},
|
||||
sendMedia: async () => {},
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.shouldProcess).toBe(false);
|
||||
expect(groupHistories.get("whatsapp:default:group:123@g.us")?.length).toBe(1);
|
||||
});
|
||||
|
||||
it("bypasses mention gating for owner /status in group chats", () => {
|
||||
const cfg = makeConfig({
|
||||
channels: {
|
||||
whatsapp: {
|
||||
allowFrom: ["+111"],
|
||||
groups: { "*": { requireMention: true } },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { result } = runGroupGating({
|
||||
cfg,
|
||||
msg: {
|
||||
id: "g-status",
|
||||
from: "123@g.us",
|
||||
conversationId: "123@g.us",
|
||||
chatId: "123@g.us",
|
||||
chatType: "group",
|
||||
to: "+2",
|
||||
body: "/status",
|
||||
senderE164: "+111",
|
||||
senderName: "Owner",
|
||||
selfE164: "+999",
|
||||
sendComposing: async () => {},
|
||||
reply: async () => {},
|
||||
sendMedia: async () => {},
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.shouldProcess).toBe(true);
|
||||
});
|
||||
|
||||
it("uses per-agent mention patterns for group gating (routing + mentionPatterns)", () => {
|
||||
const cfg = makeConfig({
|
||||
channels: {
|
||||
whatsapp: {
|
||||
allowFrom: ["*"],
|
||||
groups: { "*": { requireMention: true } },
|
||||
},
|
||||
},
|
||||
messages: {
|
||||
groupChat: { mentionPatterns: ["@global"] },
|
||||
},
|
||||
agents: {
|
||||
list: [
|
||||
{
|
||||
id: "work",
|
||||
groupChat: { mentionPatterns: ["@workbot"] },
|
||||
},
|
||||
],
|
||||
},
|
||||
bindings: [
|
||||
{
|
||||
agentId: "work",
|
||||
match: {
|
||||
provider: "whatsapp",
|
||||
peer: { kind: "group", id: "123@g.us" },
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const route = resolveAgentRoute({
|
||||
cfg,
|
||||
channel: "whatsapp",
|
||||
peer: { kind: "group", id: "123@g.us" },
|
||||
});
|
||||
expect(route.agentId).toBe("work");
|
||||
|
||||
const { result: globalMention } = runGroupGating({
|
||||
cfg,
|
||||
agentId: route.agentId,
|
||||
msg: {
|
||||
id: "g1",
|
||||
from: "123@g.us",
|
||||
conversationId: "123@g.us",
|
||||
chatId: "123@g.us",
|
||||
chatType: "group",
|
||||
to: "+2",
|
||||
body: "@global ping",
|
||||
senderE164: "+111",
|
||||
senderName: "Alice",
|
||||
selfE164: "+999",
|
||||
sendComposing: async () => {},
|
||||
reply: async () => {},
|
||||
sendMedia: async () => {},
|
||||
},
|
||||
});
|
||||
expect(globalMention.shouldProcess).toBe(false);
|
||||
|
||||
const { result: workMention } = runGroupGating({
|
||||
cfg,
|
||||
agentId: route.agentId,
|
||||
msg: {
|
||||
id: "g2",
|
||||
from: "123@g.us",
|
||||
conversationId: "123@g.us",
|
||||
chatId: "123@g.us",
|
||||
chatType: "group",
|
||||
to: "+2",
|
||||
body: "@workbot ping",
|
||||
senderE164: "+222",
|
||||
senderName: "Bob",
|
||||
selfE164: "+999",
|
||||
sendComposing: async () => {},
|
||||
reply: async () => {},
|
||||
sendMedia: async () => {},
|
||||
},
|
||||
});
|
||||
expect(workMention.shouldProcess).toBe(true);
|
||||
});
|
||||
|
||||
it("allows group messages when whatsapp groups default disables mention gating", () => {
|
||||
const cfg = makeConfig({
|
||||
channels: {
|
||||
whatsapp: {
|
||||
allowFrom: ["*"],
|
||||
groups: { "*": { requireMention: false } },
|
||||
},
|
||||
},
|
||||
messages: { groupChat: { mentionPatterns: ["@openclaw"] } },
|
||||
});
|
||||
|
||||
const { result } = runGroupGating({
|
||||
cfg,
|
||||
msg: {
|
||||
id: "g1",
|
||||
from: "123@g.us",
|
||||
conversationId: "123@g.us",
|
||||
chatId: "123@g.us",
|
||||
chatType: "group",
|
||||
to: "+2",
|
||||
body: "hello group",
|
||||
senderE164: "+111",
|
||||
senderName: "Alice",
|
||||
selfE164: "+999",
|
||||
sendComposing: async () => {},
|
||||
reply: async () => {},
|
||||
sendMedia: async () => {},
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.shouldProcess).toBe(true);
|
||||
});
|
||||
|
||||
it("blocks group messages when whatsapp groups is set without a wildcard", () => {
|
||||
const cfg = makeConfig({
|
||||
channels: {
|
||||
whatsapp: {
|
||||
allowFrom: ["*"],
|
||||
groups: {
|
||||
"999@g.us": { requireMention: false },
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { result } = runGroupGating({
|
||||
cfg,
|
||||
msg: {
|
||||
id: "g1",
|
||||
from: "123@g.us",
|
||||
conversationId: "123@g.us",
|
||||
chatId: "123@g.us",
|
||||
chatType: "group",
|
||||
to: "+2",
|
||||
body: "@workbot ping",
|
||||
senderE164: "+111",
|
||||
senderName: "Alice",
|
||||
selfE164: "+999",
|
||||
mentionedJids: ["999@s.whatsapp.net"],
|
||||
selfJid: "999@s.whatsapp.net",
|
||||
sendComposing: async () => {},
|
||||
reply: async () => {},
|
||||
sendMedia: async () => {},
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.shouldProcess).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { buildInboundLine } from "./message-line.js";
|
||||
import { buildInboundLine, formatReplyContext } from "./message-line.js";
|
||||
|
||||
describe("buildInboundLine", () => {
|
||||
it("prefixes group messages with sender", () => {
|
||||
@@ -30,4 +30,53 @@ describe("buildInboundLine", () => {
|
||||
expect(line).toContain("Bob (+15550001111):");
|
||||
expect(line).toContain("ping");
|
||||
});
|
||||
|
||||
it("includes reply-to context blocks when replyToBody is present", () => {
|
||||
const line = buildInboundLine({
|
||||
cfg: {
|
||||
agents: { defaults: { workspace: "/tmp/openclaw" } },
|
||||
channels: { whatsapp: { messagePrefix: "" } },
|
||||
} as never,
|
||||
agentId: "main",
|
||||
msg: {
|
||||
from: "+1555",
|
||||
to: "+1555",
|
||||
body: "hello",
|
||||
chatType: "direct",
|
||||
replyToId: "q1",
|
||||
replyToBody: "original",
|
||||
replyToSender: "+1999",
|
||||
} as never,
|
||||
envelope: { includeTimestamp: false },
|
||||
});
|
||||
|
||||
expect(line).toContain("[Replying to +1999 id:q1]");
|
||||
expect(line).toContain("original");
|
||||
expect(line).toContain("[/Replying]");
|
||||
});
|
||||
|
||||
it("applies the WhatsApp messagePrefix when configured", () => {
|
||||
const line = buildInboundLine({
|
||||
cfg: {
|
||||
agents: { defaults: { workspace: "/tmp/openclaw" } },
|
||||
channels: { whatsapp: { messagePrefix: "[PFX]" } },
|
||||
} as never,
|
||||
agentId: "main",
|
||||
msg: {
|
||||
from: "+1555",
|
||||
to: "+2666",
|
||||
body: "ping",
|
||||
chatType: "direct",
|
||||
} as never,
|
||||
envelope: { includeTimestamp: false },
|
||||
});
|
||||
|
||||
expect(line).toContain("[PFX] ping");
|
||||
});
|
||||
});
|
||||
|
||||
describe("formatReplyContext", () => {
|
||||
it("returns null when replyToBody is missing", () => {
|
||||
expect(formatReplyContext({} as never)).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,24 +1,49 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { expectInboundContextContract } from "../../../../test/helpers/inbound-contract.js";
|
||||
|
||||
let capturedCtx: unknown;
|
||||
let capturedDispatchParams: unknown;
|
||||
let sessionDir: string | undefined;
|
||||
let sessionStorePath: string;
|
||||
|
||||
vi.mock("../../../auto-reply/reply/provider-dispatcher.js", () => ({
|
||||
dispatchReplyWithBufferedBlockDispatcher: vi.fn(async (params: { ctx: unknown }) => {
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
dispatchReplyWithBufferedBlockDispatcher: vi.fn(async (params: any) => {
|
||||
capturedDispatchParams = params;
|
||||
capturedCtx = params.ctx;
|
||||
return { queuedFinal: false };
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("./last-route.js", () => ({
|
||||
trackBackgroundTask: () => undefined,
|
||||
updateLastRouteInBackground: vi.fn(),
|
||||
}));
|
||||
|
||||
import { processMessage } from "./process-message.js";
|
||||
|
||||
describe("web processMessage inbound contract", () => {
|
||||
it("passes a finalized MsgContext to the dispatcher", async () => {
|
||||
beforeEach(async () => {
|
||||
capturedCtx = undefined;
|
||||
capturedDispatchParams = undefined;
|
||||
sessionDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-process-message-"));
|
||||
sessionStorePath = path.join(sessionDir, "sessions.json");
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
if (sessionDir) {
|
||||
await fs.rm(sessionDir, { recursive: true, force: true });
|
||||
sessionDir = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
it("passes a finalized MsgContext to the dispatcher", async () => {
|
||||
await processMessage({
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
cfg: { messages: {} } as any,
|
||||
cfg: { messages: {}, session: { store: sessionStorePath } } as any,
|
||||
msg: {
|
||||
id: "msg1",
|
||||
from: "123@g.us",
|
||||
@@ -61,4 +86,174 @@ describe("web processMessage inbound contract", () => {
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
expectInboundContextContract(capturedCtx as any);
|
||||
});
|
||||
|
||||
it("falls back SenderId to SenderE164 when senderJid is empty", async () => {
|
||||
capturedCtx = undefined;
|
||||
|
||||
await processMessage({
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
cfg: { messages: {}, session: { store: sessionStorePath } } as any,
|
||||
msg: {
|
||||
id: "msg1",
|
||||
from: "+1000",
|
||||
to: "+2000",
|
||||
chatType: "direct",
|
||||
body: "hi",
|
||||
senderJid: "",
|
||||
senderE164: "+1000",
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
} as any,
|
||||
route: {
|
||||
agentId: "main",
|
||||
accountId: "default",
|
||||
sessionKey: "agent:main:whatsapp:direct:+1000",
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
} as any,
|
||||
groupHistoryKey: "+1000",
|
||||
groupHistories: new Map(),
|
||||
groupMemberNames: new Map(),
|
||||
connectionId: "conn",
|
||||
verbose: false,
|
||||
maxMediaBytes: 1,
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
replyResolver: (async () => undefined) as any,
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
replyLogger: { info: () => {}, warn: () => {}, error: () => {}, debug: () => {} } as any,
|
||||
backgroundTasks: new Set(),
|
||||
rememberSentText: (_text: string | undefined, _opts: unknown) => {},
|
||||
echoHas: () => false,
|
||||
echoForget: () => {},
|
||||
buildCombinedEchoKey: () => "echo",
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
} as any);
|
||||
|
||||
expect(capturedCtx).toBeTruthy();
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
const ctx = capturedCtx as any;
|
||||
expect(ctx.SenderId).toBe("+1000");
|
||||
expect(ctx.SenderE164).toBe("+1000");
|
||||
expect(ctx.OriginatingChannel).toBe("whatsapp");
|
||||
expect(ctx.OriginatingTo).toBe("+1000");
|
||||
expect(ctx.To).toBe("+2000");
|
||||
expect(ctx.OriginatingTo).not.toBe(ctx.To);
|
||||
});
|
||||
|
||||
it("defaults responsePrefix to identity name in self-chats when unset", async () => {
|
||||
capturedDispatchParams = undefined;
|
||||
|
||||
await processMessage({
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
cfg: {
|
||||
agents: {
|
||||
list: [
|
||||
{
|
||||
id: "main",
|
||||
default: true,
|
||||
identity: { name: "Mainbot", emoji: "🦞", theme: "space lobster" },
|
||||
},
|
||||
],
|
||||
},
|
||||
messages: {},
|
||||
session: { store: sessionStorePath },
|
||||
} as any,
|
||||
msg: {
|
||||
id: "msg1",
|
||||
from: "+1555",
|
||||
to: "+1555",
|
||||
selfE164: "+1555",
|
||||
chatType: "direct",
|
||||
body: "hi",
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
} as any,
|
||||
route: {
|
||||
agentId: "main",
|
||||
accountId: "default",
|
||||
sessionKey: "agent:main:whatsapp:direct:+1555",
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
} as any,
|
||||
groupHistoryKey: "+1555",
|
||||
groupHistories: new Map(),
|
||||
groupMemberNames: new Map(),
|
||||
connectionId: "conn",
|
||||
verbose: false,
|
||||
maxMediaBytes: 1,
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
replyResolver: (async () => undefined) as any,
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
replyLogger: { info: () => {}, warn: () => {}, error: () => {}, debug: () => {} } as any,
|
||||
backgroundTasks: new Set(),
|
||||
rememberSentText: (_text: string | undefined, _opts: unknown) => {},
|
||||
echoHas: () => false,
|
||||
echoForget: () => {},
|
||||
buildCombinedEchoKey: () => "echo",
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
} as any);
|
||||
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
const dispatcherOptions = (capturedDispatchParams as any)?.dispatcherOptions;
|
||||
expect(dispatcherOptions?.responsePrefix).toBe("[Mainbot]");
|
||||
});
|
||||
|
||||
it("clears pending group history when the dispatcher does not queue a final reply", async () => {
|
||||
capturedCtx = undefined;
|
||||
const groupHistories = new Map<string, Array<{ sender: string; body: string }>>([
|
||||
[
|
||||
"whatsapp:default:group:123@g.us",
|
||||
[
|
||||
{
|
||||
sender: "Alice (+111)",
|
||||
body: "first",
|
||||
},
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
await processMessage({
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
cfg: {
|
||||
messages: {},
|
||||
session: { store: sessionStorePath },
|
||||
} as any,
|
||||
msg: {
|
||||
id: "g1",
|
||||
from: "123@g.us",
|
||||
conversationId: "123@g.us",
|
||||
to: "+2000",
|
||||
chatType: "group",
|
||||
chatId: "123@g.us",
|
||||
body: "second",
|
||||
senderName: "Bob",
|
||||
senderE164: "+222",
|
||||
selfE164: "+999",
|
||||
sendComposing: async () => {},
|
||||
reply: async () => {},
|
||||
sendMedia: async () => {},
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
} as any,
|
||||
route: {
|
||||
agentId: "main",
|
||||
accountId: "default",
|
||||
sessionKey: "agent:main:whatsapp:group:123@g.us",
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
} as any,
|
||||
groupHistoryKey: "whatsapp:default:group:123@g.us",
|
||||
groupHistories: groupHistories as never,
|
||||
groupMemberNames: new Map(),
|
||||
connectionId: "conn",
|
||||
verbose: false,
|
||||
maxMediaBytes: 1,
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
replyResolver: (async () => undefined) as any,
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
replyLogger: { info: () => {}, warn: () => {}, error: () => {}, debug: () => {} } as any,
|
||||
backgroundTasks: new Set(),
|
||||
rememberSentText: (_text: string | undefined, _opts: unknown) => {},
|
||||
echoHas: () => false,
|
||||
echoForget: () => {},
|
||||
buildCombinedEchoKey: () => "echo",
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
} as any);
|
||||
|
||||
expect(groupHistories.get("whatsapp:default:group:123@g.us") ?? []).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user