mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-07 07:21:36 +00:00
feat: multi-agent routing + multi-account providers
This commit is contained in:
@@ -105,7 +105,7 @@ const makeSessionStore = async (
|
||||
};
|
||||
|
||||
describe("partial reply gating", () => {
|
||||
it("does not send partial replies for WhatsApp surface", async () => {
|
||||
it("does not send partial replies for WhatsApp provider", async () => {
|
||||
const reply = vi.fn().mockResolvedValue(undefined);
|
||||
const sendComposing = vi.fn().mockResolvedValue(undefined);
|
||||
const sendMedia = vi.fn().mockResolvedValue(undefined);
|
||||
@@ -153,8 +153,9 @@ describe("partial reply gating", () => {
|
||||
|
||||
it("updates last-route for direct chats without senderE164", async () => {
|
||||
const now = Date.now();
|
||||
const mainSessionKey = "agent:main:main";
|
||||
const store = await makeSessionStore({
|
||||
main: { sessionId: "sid", updatedAt: now - 1 },
|
||||
[mainSessionKey]: { sessionId: "sid", updatedAt: now - 1 },
|
||||
});
|
||||
|
||||
const replyResolver = vi.fn().mockResolvedValue(undefined);
|
||||
@@ -163,7 +164,7 @@ describe("partial reply gating", () => {
|
||||
whatsapp: {
|
||||
allowFrom: ["*"],
|
||||
},
|
||||
session: { store: store.storePath, mainKey: "main" },
|
||||
session: { store: store.storePath },
|
||||
};
|
||||
|
||||
setLoadConfigMock(mockConfig);
|
||||
@@ -190,18 +191,95 @@ describe("partial reply gating", () => {
|
||||
replyResolver,
|
||||
);
|
||||
|
||||
let stored: { main?: { lastChannel?: string; lastTo?: string } } | null =
|
||||
null;
|
||||
let stored: Record<
|
||||
string,
|
||||
{ lastProvider?: string; lastTo?: string }
|
||||
> | null = null;
|
||||
for (let attempt = 0; attempt < 50; attempt += 1) {
|
||||
stored = JSON.parse(await fs.readFile(store.storePath, "utf8")) as {
|
||||
main?: { lastChannel?: string; lastTo?: string };
|
||||
};
|
||||
if (stored.main?.lastChannel && stored.main?.lastTo) break;
|
||||
stored = JSON.parse(await fs.readFile(store.storePath, "utf8")) as Record<
|
||||
string,
|
||||
{ lastProvider?: string; lastTo?: string }
|
||||
>;
|
||||
if (
|
||||
stored[mainSessionKey]?.lastProvider &&
|
||||
stored[mainSessionKey]?.lastTo
|
||||
)
|
||||
break;
|
||||
await new Promise((resolve) => setTimeout(resolve, 5));
|
||||
}
|
||||
if (!stored) throw new Error("store not loaded");
|
||||
expect(stored.main?.lastChannel).toBe("whatsapp");
|
||||
expect(stored.main?.lastTo).toBe("+1000");
|
||||
expect(stored[mainSessionKey]?.lastProvider).toBe("whatsapp");
|
||||
expect(stored[mainSessionKey]?.lastTo).toBe("+1000");
|
||||
|
||||
resetLoadConfigMock();
|
||||
await store.cleanup();
|
||||
});
|
||||
|
||||
it("updates last-route for group chats with account id", async () => {
|
||||
const now = Date.now();
|
||||
const groupSessionKey = "agent:main:whatsapp:group:123@g.us";
|
||||
const store = await makeSessionStore({
|
||||
[groupSessionKey]: { sessionId: "sid", updatedAt: now - 1 },
|
||||
});
|
||||
|
||||
const replyResolver = vi.fn().mockResolvedValue(undefined);
|
||||
|
||||
const mockConfig: ClawdbotConfig = {
|
||||
whatsapp: {
|
||||
allowFrom: ["*"],
|
||||
},
|
||||
session: { store: store.storePath },
|
||||
};
|
||||
|
||||
setLoadConfigMock(mockConfig);
|
||||
|
||||
await monitorWebProvider(
|
||||
false,
|
||||
async ({ onMessage }) => {
|
||||
await onMessage({
|
||||
id: "g1",
|
||||
from: "123@g.us",
|
||||
conversationId: "123@g.us",
|
||||
to: "+2000",
|
||||
body: "hello",
|
||||
timestamp: now,
|
||||
chatType: "group",
|
||||
chatId: "123@g.us",
|
||||
accountId: "work",
|
||||
senderE164: "+1000",
|
||||
senderName: "Alice",
|
||||
selfE164: "+2000",
|
||||
sendComposing: vi.fn().mockResolvedValue(undefined),
|
||||
reply: vi.fn().mockResolvedValue(undefined),
|
||||
sendMedia: vi.fn().mockResolvedValue(undefined),
|
||||
});
|
||||
return { close: vi.fn().mockResolvedValue(undefined) };
|
||||
},
|
||||
false,
|
||||
replyResolver,
|
||||
);
|
||||
|
||||
let stored: Record<
|
||||
string,
|
||||
{ lastProvider?: string; lastTo?: string; lastAccountId?: string }
|
||||
> | null = null;
|
||||
for (let attempt = 0; attempt < 50; attempt += 1) {
|
||||
stored = JSON.parse(await fs.readFile(store.storePath, "utf8")) as Record<
|
||||
string,
|
||||
{ lastProvider?: string; lastTo?: string; lastAccountId?: string }
|
||||
>;
|
||||
if (
|
||||
stored[groupSessionKey]?.lastProvider &&
|
||||
stored[groupSessionKey]?.lastTo &&
|
||||
stored[groupSessionKey]?.lastAccountId
|
||||
)
|
||||
break;
|
||||
await new Promise((resolve) => setTimeout(resolve, 5));
|
||||
}
|
||||
if (!stored) throw new Error("store not loaded");
|
||||
expect(stored[groupSessionKey]?.lastProvider).toBe("whatsapp");
|
||||
expect(stored[groupSessionKey]?.lastTo).toBe("123@g.us");
|
||||
expect(stored[groupSessionKey]?.lastAccountId).toBe("work");
|
||||
|
||||
resetLoadConfigMock();
|
||||
await store.cleanup();
|
||||
@@ -1215,7 +1293,7 @@ describe("web auto-reply", () => {
|
||||
.mockResolvedValueOnce({ text: "ok" });
|
||||
|
||||
const { storePath, cleanup } = await makeSessionStore({
|
||||
"whatsapp:group:123@g.us": {
|
||||
"agent:main:whatsapp:group:123@g.us": {
|
||||
sessionId: "g-1",
|
||||
updatedAt: Date.now(),
|
||||
groupActivation: "always",
|
||||
|
||||
Reference in New Issue
Block a user