mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-10 12:24:59 +00:00
Discord: add unit tests for role-based agent routing
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import { describe, expect, test } from "vitest";
|
import { describe, expect, test } from "vitest";
|
||||||
|
import type { ChatType } from "../channels/chat-type.js";
|
||||||
import type { OpenClawConfig } from "../config/config.js";
|
import type { OpenClawConfig } from "../config/config.js";
|
||||||
import { resolveAgentRoute } from "./resolve-route.js";
|
import { resolveAgentRoute } from "./resolve-route.js";
|
||||||
|
|
||||||
@@ -419,7 +420,7 @@ describe("backward compatibility: peer.kind dm → direct", () => {
|
|||||||
match: {
|
match: {
|
||||||
channel: "whatsapp",
|
channel: "whatsapp",
|
||||||
// Legacy config uses "dm" instead of "direct"
|
// Legacy config uses "dm" instead of "direct"
|
||||||
peer: { kind: "dm", id: "+15551234567" },
|
peer: { kind: "dm" as ChatType, id: "+15551234567" },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -435,3 +436,138 @@ describe("backward compatibility: peer.kind dm → direct", () => {
|
|||||||
expect(route.matchedBy).toBe("binding.peer");
|
expect(route.matchedBy).toBe("binding.peer");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("role-based agent routing", () => {
|
||||||
|
test("guild+roles binding matches when member has matching role", () => {
|
||||||
|
const cfg: OpenClawConfig = {
|
||||||
|
bindings: [{ agentId: "opus", match: { channel: "discord", guildId: "g1", roles: ["r1"] } }],
|
||||||
|
};
|
||||||
|
const route = resolveAgentRoute({
|
||||||
|
cfg,
|
||||||
|
channel: "discord",
|
||||||
|
guildId: "g1",
|
||||||
|
memberRoleIds: ["r1"],
|
||||||
|
peer: { kind: "channel", id: "c1" },
|
||||||
|
});
|
||||||
|
expect(route.agentId).toBe("opus");
|
||||||
|
expect(route.matchedBy).toBe("binding.guild+roles");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("guild+roles binding skipped when no matching role", () => {
|
||||||
|
const cfg: OpenClawConfig = {
|
||||||
|
bindings: [{ agentId: "opus", match: { channel: "discord", guildId: "g1", roles: ["r1"] } }],
|
||||||
|
};
|
||||||
|
const route = resolveAgentRoute({
|
||||||
|
cfg,
|
||||||
|
channel: "discord",
|
||||||
|
guildId: "g1",
|
||||||
|
memberRoleIds: ["r2"],
|
||||||
|
peer: { kind: "channel", id: "c1" },
|
||||||
|
});
|
||||||
|
expect(route.agentId).toBe("main");
|
||||||
|
expect(route.matchedBy).toBe("default");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("guild+roles is more specific than guild-only", () => {
|
||||||
|
const cfg: OpenClawConfig = {
|
||||||
|
bindings: [
|
||||||
|
{ agentId: "opus", match: { channel: "discord", guildId: "g1", roles: ["r1"] } },
|
||||||
|
{ agentId: "sonnet", match: { channel: "discord", guildId: "g1" } },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const route = resolveAgentRoute({
|
||||||
|
cfg,
|
||||||
|
channel: "discord",
|
||||||
|
guildId: "g1",
|
||||||
|
memberRoleIds: ["r1"],
|
||||||
|
peer: { kind: "channel", id: "c1" },
|
||||||
|
});
|
||||||
|
expect(route.agentId).toBe("opus");
|
||||||
|
expect(route.matchedBy).toBe("binding.guild+roles");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("peer binding still beats guild+roles", () => {
|
||||||
|
const cfg: OpenClawConfig = {
|
||||||
|
bindings: [
|
||||||
|
{
|
||||||
|
agentId: "peer-agent",
|
||||||
|
match: { channel: "discord", peer: { kind: "channel", id: "c1" } },
|
||||||
|
},
|
||||||
|
{ agentId: "roles-agent", match: { channel: "discord", guildId: "g1", roles: ["r1"] } },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const route = resolveAgentRoute({
|
||||||
|
cfg,
|
||||||
|
channel: "discord",
|
||||||
|
guildId: "g1",
|
||||||
|
memberRoleIds: ["r1"],
|
||||||
|
peer: { kind: "channel", id: "c1" },
|
||||||
|
});
|
||||||
|
expect(route.agentId).toBe("peer-agent");
|
||||||
|
expect(route.matchedBy).toBe("binding.peer");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("no memberRoleIds → guild+roles doesn't match", () => {
|
||||||
|
const cfg: OpenClawConfig = {
|
||||||
|
bindings: [{ agentId: "opus", match: { channel: "discord", guildId: "g1", roles: ["r1"] } }],
|
||||||
|
};
|
||||||
|
const route = resolveAgentRoute({
|
||||||
|
cfg,
|
||||||
|
channel: "discord",
|
||||||
|
guildId: "g1",
|
||||||
|
peer: { kind: "channel", id: "c1" },
|
||||||
|
});
|
||||||
|
expect(route.agentId).toBe("main");
|
||||||
|
expect(route.matchedBy).toBe("default");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("first matching binding wins with multiple role bindings", () => {
|
||||||
|
const cfg: OpenClawConfig = {
|
||||||
|
bindings: [
|
||||||
|
{ agentId: "opus", match: { channel: "discord", guildId: "g1", roles: ["r1"] } },
|
||||||
|
{ agentId: "sonnet", match: { channel: "discord", guildId: "g1", roles: ["r2"] } },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const route = resolveAgentRoute({
|
||||||
|
cfg,
|
||||||
|
channel: "discord",
|
||||||
|
guildId: "g1",
|
||||||
|
memberRoleIds: ["r1", "r2"],
|
||||||
|
peer: { kind: "channel", id: "c1" },
|
||||||
|
});
|
||||||
|
expect(route.agentId).toBe("opus");
|
||||||
|
expect(route.matchedBy).toBe("binding.guild+roles");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("empty roles array treated as no role restriction", () => {
|
||||||
|
const cfg: OpenClawConfig = {
|
||||||
|
bindings: [{ agentId: "opus", match: { channel: "discord", guildId: "g1", roles: [] } }],
|
||||||
|
};
|
||||||
|
const route = resolveAgentRoute({
|
||||||
|
cfg,
|
||||||
|
channel: "discord",
|
||||||
|
guildId: "g1",
|
||||||
|
memberRoleIds: ["r1"],
|
||||||
|
peer: { kind: "channel", id: "c1" },
|
||||||
|
});
|
||||||
|
expect(route.agentId).toBe("opus");
|
||||||
|
expect(route.matchedBy).toBe("binding.guild");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("CRITICAL: guild+roles binding NOT matched as guild-only when roles don't match", () => {
|
||||||
|
const cfg: OpenClawConfig = {
|
||||||
|
bindings: [
|
||||||
|
{ agentId: "opus", match: { channel: "discord", guildId: "g1", roles: ["admin"] } },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const route = resolveAgentRoute({
|
||||||
|
cfg,
|
||||||
|
channel: "discord",
|
||||||
|
guildId: "g1",
|
||||||
|
memberRoleIds: ["regular"],
|
||||||
|
peer: { kind: "channel", id: "c1" },
|
||||||
|
});
|
||||||
|
expect(route.agentId).toBe("main");
|
||||||
|
expect(route.matchedBy).toBe("default");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user