mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 11:40:42 +00:00
test: use synthetic outbound dispatch fixtures
This commit is contained in:
@@ -41,7 +41,7 @@ vi.mock("./outbound-session.js", () => ({
|
||||
|
||||
vi.mock("../../channels/plugins/bootstrap-registry.js", () => ({
|
||||
getBootstrapChannelPlugin: (id: string) =>
|
||||
id === "feishu"
|
||||
id === "actionhub"
|
||||
? {
|
||||
actions: {
|
||||
messageActionTargetAliases: {
|
||||
@@ -164,14 +164,14 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
}),
|
||||
);
|
||||
|
||||
const feishuLikePlugin: ChannelPlugin = {
|
||||
id: "feishu",
|
||||
const actionHubPlugin: ChannelPlugin = {
|
||||
id: "actionhub",
|
||||
meta: {
|
||||
id: "feishu",
|
||||
label: "Feishu",
|
||||
selectionLabel: "Feishu",
|
||||
docsPath: "/channels/feishu",
|
||||
blurb: "Feishu action dispatch test plugin.",
|
||||
id: "actionhub",
|
||||
label: "Action Hub",
|
||||
selectionLabel: "Action Hub",
|
||||
docsPath: "/channels/actionhub",
|
||||
blurb: "Action Hub action dispatch test plugin.",
|
||||
},
|
||||
capabilities: { chatTypes: ["direct", "channel"] },
|
||||
config: createAlwaysConfiguredPluginConfig(),
|
||||
@@ -192,9 +192,9 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
setActivePluginRegistry(
|
||||
createTestRegistry([
|
||||
{
|
||||
pluginId: "feishu",
|
||||
pluginId: "actionhub",
|
||||
source: "test",
|
||||
plugin: feishuLikePlugin,
|
||||
plugin: actionHubPlugin,
|
||||
},
|
||||
]),
|
||||
);
|
||||
@@ -207,18 +207,18 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
vi.unstubAllEnvs();
|
||||
});
|
||||
|
||||
it("dispatches messageId/chatId-based Feishu actions through the shared runner", async () => {
|
||||
it("dispatches messageId/chatId-based plugin actions through the shared runner", async () => {
|
||||
await runMessageAction({
|
||||
cfg: {
|
||||
channels: {
|
||||
feishu: {
|
||||
actionhub: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
action: "pin",
|
||||
params: {
|
||||
channel: "feishu",
|
||||
channel: "actionhub",
|
||||
messageId: "om_123",
|
||||
},
|
||||
dryRun: false,
|
||||
@@ -227,14 +227,14 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
await runMessageAction({
|
||||
cfg: {
|
||||
channels: {
|
||||
feishu: {
|
||||
actionhub: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
action: "list-pins",
|
||||
params: {
|
||||
channel: "feishu",
|
||||
channel: "actionhub",
|
||||
chatId: "oc_123",
|
||||
},
|
||||
dryRun: false,
|
||||
@@ -268,14 +268,14 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
await runMessageAction({
|
||||
cfg: {
|
||||
channels: {
|
||||
feishu: {
|
||||
actionhub: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
action: "pin",
|
||||
params: {
|
||||
channel: "feishu",
|
||||
channel: "actionhub",
|
||||
messageId: "om_123",
|
||||
},
|
||||
defaultAccountId: "ops",
|
||||
@@ -285,7 +285,7 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
agentId: "alpha",
|
||||
toolContext: {
|
||||
currentChannelId: "oc_123",
|
||||
currentChannelProvider: "feishu",
|
||||
currentChannelProvider: "actionhub",
|
||||
currentThreadTs: "thread-456",
|
||||
currentMessageId: "msg-789",
|
||||
},
|
||||
@@ -303,7 +303,7 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
mediaLocalRoots: expect.arrayContaining([expectedWorkspaceRoot]),
|
||||
toolContext: expect.objectContaining({
|
||||
currentChannelId: "oc_123",
|
||||
currentChannelProvider: "feishu",
|
||||
currentChannelProvider: "actionhub",
|
||||
currentThreadTs: "thread-456",
|
||||
currentMessageId: "msg-789",
|
||||
}),
|
||||
@@ -319,13 +319,13 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
}),
|
||||
);
|
||||
const gatewayPlugin: ChannelPlugin = {
|
||||
id: "whatsapp",
|
||||
id: "gatewaychat",
|
||||
meta: {
|
||||
id: "whatsapp",
|
||||
label: "WhatsApp",
|
||||
selectionLabel: "WhatsApp",
|
||||
docsPath: "/channels/whatsapp",
|
||||
blurb: "WhatsApp reaction test plugin.",
|
||||
id: "gatewaychat",
|
||||
label: "Gateway Chat",
|
||||
selectionLabel: "Gateway Chat",
|
||||
docsPath: "/channels/gatewaychat",
|
||||
blurb: "Gateway Chat reaction test plugin.",
|
||||
},
|
||||
capabilities: { chatTypes: ["direct"], reactions: true },
|
||||
config: createAlwaysConfiguredPluginConfig(),
|
||||
@@ -339,7 +339,7 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
setActivePluginRegistry(
|
||||
createTestRegistry([
|
||||
{
|
||||
pluginId: "whatsapp",
|
||||
pluginId: "gatewaychat",
|
||||
source: "test",
|
||||
plugin: gatewayPlugin,
|
||||
},
|
||||
@@ -353,14 +353,14 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
const result = await runMessageAction({
|
||||
cfg: {
|
||||
channels: {
|
||||
whatsapp: {
|
||||
gatewaychat: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
action: "react",
|
||||
params: {
|
||||
channel: "whatsapp",
|
||||
channel: "gatewaychat",
|
||||
to: "+15551234567",
|
||||
chatJid: "+15551234567",
|
||||
messageId: "wamid.1",
|
||||
@@ -371,7 +371,7 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
sessionId: "session-123",
|
||||
agentId: "alpha",
|
||||
toolContext: {
|
||||
currentChannelProvider: "whatsapp",
|
||||
currentChannelProvider: "gatewaychat",
|
||||
currentMessageId: "wamid.1",
|
||||
},
|
||||
gateway: {
|
||||
@@ -385,14 +385,14 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
expect.objectContaining({
|
||||
method: "message.action",
|
||||
params: expect.objectContaining({
|
||||
channel: "whatsapp",
|
||||
channel: "gatewaychat",
|
||||
action: "react",
|
||||
requesterSenderId: "trusted-user",
|
||||
sessionKey: "agent:alpha:main",
|
||||
sessionId: "session-123",
|
||||
agentId: "alpha",
|
||||
toolContext: expect.objectContaining({
|
||||
currentChannelProvider: "whatsapp",
|
||||
currentChannelProvider: "gatewaychat",
|
||||
currentMessageId: "wamid.1",
|
||||
}),
|
||||
idempotencyKey: "idem-gateway-action",
|
||||
@@ -402,7 +402,7 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
expect(handleAction).not.toHaveBeenCalled();
|
||||
expect(result).toMatchObject({
|
||||
kind: "action",
|
||||
channel: "whatsapp",
|
||||
channel: "gatewaychat",
|
||||
action: "react",
|
||||
handledBy: "plugin",
|
||||
payload: {
|
||||
@@ -420,13 +420,13 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
}),
|
||||
);
|
||||
const policyPlugin: ChannelPlugin = {
|
||||
id: "feishu",
|
||||
id: "policydest",
|
||||
meta: {
|
||||
id: "feishu",
|
||||
label: "Feishu",
|
||||
selectionLabel: "Feishu",
|
||||
docsPath: "/channels/feishu",
|
||||
blurb: "Feishu policy test plugin.",
|
||||
id: "policydest",
|
||||
label: "Policy Destination",
|
||||
selectionLabel: "Policy Destination",
|
||||
docsPath: "/channels/policydest",
|
||||
blurb: "Policy destination test plugin.",
|
||||
},
|
||||
capabilities: { chatTypes: ["direct", "channel"], media: true },
|
||||
config: createAlwaysConfiguredPluginConfig(),
|
||||
@@ -445,7 +445,7 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
setActivePluginRegistry(
|
||||
createTestRegistry([
|
||||
{
|
||||
pluginId: "feishu",
|
||||
pluginId: "policydest",
|
||||
source: "test",
|
||||
plugin: policyPlugin,
|
||||
},
|
||||
@@ -456,10 +456,10 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
cfg: {
|
||||
tools: { allow: ["read"] },
|
||||
channels: {
|
||||
feishu: {
|
||||
policydest: {
|
||||
enabled: true,
|
||||
},
|
||||
whatsapp: {
|
||||
requestchat: {
|
||||
groups: {
|
||||
ops: {
|
||||
toolsBySender: {
|
||||
@@ -474,13 +474,13 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
} as OpenClawConfig,
|
||||
action: "send",
|
||||
params: {
|
||||
channel: "feishu",
|
||||
channel: "policydest",
|
||||
target: "oc_123",
|
||||
message: "hello",
|
||||
media: "/tmp/host.png",
|
||||
},
|
||||
requesterSenderId: "trusted-user",
|
||||
sessionKey: "agent:alpha:whatsapp:group:ops",
|
||||
sessionKey: "agent:alpha:requestchat:group:ops",
|
||||
dryRun: false,
|
||||
});
|
||||
|
||||
@@ -497,13 +497,13 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
}),
|
||||
);
|
||||
const policyPlugin: ChannelPlugin = {
|
||||
id: "feishu",
|
||||
id: "policydest",
|
||||
meta: {
|
||||
id: "feishu",
|
||||
label: "Feishu",
|
||||
selectionLabel: "Feishu",
|
||||
docsPath: "/channels/feishu",
|
||||
blurb: "Feishu username policy test plugin.",
|
||||
id: "policydest",
|
||||
label: "Policy Destination",
|
||||
selectionLabel: "Policy Destination",
|
||||
docsPath: "/channels/policydest",
|
||||
blurb: "Policy destination username test plugin.",
|
||||
},
|
||||
capabilities: { chatTypes: ["direct", "channel"], media: true },
|
||||
config: createAlwaysConfiguredPluginConfig(),
|
||||
@@ -522,7 +522,7 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
setActivePluginRegistry(
|
||||
createTestRegistry([
|
||||
{
|
||||
pluginId: "feishu",
|
||||
pluginId: "policydest",
|
||||
source: "test",
|
||||
plugin: policyPlugin,
|
||||
},
|
||||
@@ -533,10 +533,10 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
cfg: {
|
||||
tools: { allow: ["read"] },
|
||||
channels: {
|
||||
feishu: {
|
||||
policydest: {
|
||||
enabled: true,
|
||||
},
|
||||
whatsapp: {
|
||||
requestchat: {
|
||||
groups: {
|
||||
ops: {
|
||||
toolsBySender: {
|
||||
@@ -551,13 +551,13 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
} as OpenClawConfig,
|
||||
action: "send",
|
||||
params: {
|
||||
channel: "feishu",
|
||||
channel: "policydest",
|
||||
target: "oc_123",
|
||||
message: "hello",
|
||||
media: "/tmp/host.png",
|
||||
},
|
||||
requesterSenderUsername: "alice_u",
|
||||
sessionKey: "agent:alpha:whatsapp:group:ops",
|
||||
sessionKey: "agent:alpha:requestchat:group:ops",
|
||||
dryRun: false,
|
||||
});
|
||||
|
||||
@@ -574,13 +574,13 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
}),
|
||||
);
|
||||
const policyPlugin: ChannelPlugin = {
|
||||
id: "feishu",
|
||||
id: "policydest",
|
||||
meta: {
|
||||
id: "feishu",
|
||||
label: "Feishu",
|
||||
selectionLabel: "Feishu",
|
||||
docsPath: "/channels/feishu",
|
||||
blurb: "Feishu account policy test plugin.",
|
||||
id: "policydest",
|
||||
label: "Policy Destination",
|
||||
selectionLabel: "Policy Destination",
|
||||
docsPath: "/channels/policydest",
|
||||
blurb: "Policy destination account test plugin.",
|
||||
},
|
||||
capabilities: { chatTypes: ["direct", "channel"], media: true },
|
||||
config: createAlwaysConfiguredPluginConfig(),
|
||||
@@ -599,7 +599,7 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
setActivePluginRegistry(
|
||||
createTestRegistry([
|
||||
{
|
||||
pluginId: "feishu",
|
||||
pluginId: "policydest",
|
||||
source: "test",
|
||||
plugin: policyPlugin,
|
||||
},
|
||||
@@ -610,10 +610,10 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
cfg: {
|
||||
tools: { allow: ["read"] },
|
||||
channels: {
|
||||
feishu: {
|
||||
policydest: {
|
||||
enabled: true,
|
||||
},
|
||||
whatsapp: {
|
||||
requestchat: {
|
||||
accounts: {
|
||||
source: {
|
||||
groups: {
|
||||
@@ -643,7 +643,7 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
} as OpenClawConfig,
|
||||
action: "send",
|
||||
params: {
|
||||
channel: "feishu",
|
||||
channel: "policydest",
|
||||
accountId: "destination",
|
||||
target: "oc_123",
|
||||
message: "hello",
|
||||
@@ -651,7 +651,7 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
},
|
||||
requesterAccountId: "source",
|
||||
requesterSenderId: "trusted-user",
|
||||
sessionKey: "agent:alpha:whatsapp:group:ops",
|
||||
sessionKey: "agent:alpha:requestchat:group:ops",
|
||||
dryRun: false,
|
||||
});
|
||||
|
||||
@@ -669,13 +669,13 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
}),
|
||||
);
|
||||
const policyPlugin: ChannelPlugin = {
|
||||
id: "whatsapp",
|
||||
id: "policychat",
|
||||
meta: {
|
||||
id: "whatsapp",
|
||||
label: "WhatsApp",
|
||||
selectionLabel: "WhatsApp",
|
||||
docsPath: "/channels/whatsapp",
|
||||
blurb: "WhatsApp account policy fallback test plugin.",
|
||||
id: "policychat",
|
||||
label: "Policy Chat",
|
||||
selectionLabel: "Policy Chat",
|
||||
docsPath: "/channels/policychat",
|
||||
blurb: "Policy chat account fallback test plugin.",
|
||||
},
|
||||
capabilities: { chatTypes: ["direct", "channel"], media: true },
|
||||
config: createAlwaysConfiguredPluginConfig(),
|
||||
@@ -694,7 +694,7 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
setActivePluginRegistry(
|
||||
createTestRegistry([
|
||||
{
|
||||
pluginId: "whatsapp",
|
||||
pluginId: "policychat",
|
||||
source: "test",
|
||||
plugin: policyPlugin,
|
||||
},
|
||||
@@ -705,7 +705,7 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
cfg: {
|
||||
tools: { allow: ["read"] },
|
||||
channels: {
|
||||
whatsapp: {
|
||||
policychat: {
|
||||
enabled: true,
|
||||
accounts: {
|
||||
source: {
|
||||
@@ -725,14 +725,14 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
} as OpenClawConfig,
|
||||
action: "send",
|
||||
params: {
|
||||
channel: "whatsapp",
|
||||
channel: "policychat",
|
||||
accountId: "source",
|
||||
target: "group:ops",
|
||||
message: "hello",
|
||||
media: "/tmp/host.png",
|
||||
},
|
||||
requesterSenderId: "trusted-user",
|
||||
sessionKey: "agent:alpha:whatsapp:group:ops",
|
||||
sessionKey: "agent:alpha:policychat:group:ops",
|
||||
dryRun: false,
|
||||
});
|
||||
|
||||
@@ -824,7 +824,7 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("telegram plugin poll forwarding", () => {
|
||||
describe("poll plugin forwarding", () => {
|
||||
const handleAction = vi.fn(async ({ params }: { params: Record<string, unknown> }) =>
|
||||
jsonResult({
|
||||
ok: true,
|
||||
@@ -839,10 +839,10 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
}),
|
||||
);
|
||||
|
||||
const telegramPollPlugin = createPollForwardingPlugin({
|
||||
pluginId: "telegram",
|
||||
label: "Telegram",
|
||||
blurb: "Telegram poll forwarding test plugin.",
|
||||
const pollChatPlugin = createPollForwardingPlugin({
|
||||
pluginId: "pollchat",
|
||||
label: "Poll Chat",
|
||||
blurb: "Poll chat forwarding test plugin.",
|
||||
handleAction,
|
||||
});
|
||||
|
||||
@@ -850,9 +850,9 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
setActivePluginRegistry(
|
||||
createTestRegistry([
|
||||
{
|
||||
pluginId: "telegram",
|
||||
pluginId: "pollchat",
|
||||
source: "test",
|
||||
plugin: telegramPollPlugin,
|
||||
plugin: pollChatPlugin,
|
||||
},
|
||||
]),
|
||||
);
|
||||
@@ -864,19 +864,19 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("forwards telegram poll params through plugin dispatch", async () => {
|
||||
it("forwards poll params through plugin dispatch", async () => {
|
||||
const result = await runMessageAction({
|
||||
cfg: {
|
||||
channels: {
|
||||
telegram: {
|
||||
pollchat: {
|
||||
botToken: "tok",
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
action: "poll",
|
||||
params: {
|
||||
channel: "telegram",
|
||||
target: "telegram:123",
|
||||
channel: "pollchat",
|
||||
target: "pollchat:123",
|
||||
pollQuestion: "Lunch?",
|
||||
pollOption: ["Pizza", "Sushi"],
|
||||
pollDurationSeconds: 120,
|
||||
@@ -891,9 +891,9 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
expect(handleAction).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
action: "poll",
|
||||
channel: "telegram",
|
||||
channel: "pollchat",
|
||||
params: expect.objectContaining({
|
||||
to: "telegram:123",
|
||||
to: "pollchat:123",
|
||||
pollQuestion: "Lunch?",
|
||||
pollOption: ["Pizza", "Sushi"],
|
||||
pollDurationSeconds: 120,
|
||||
@@ -905,7 +905,7 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
expect(result.payload).toMatchObject({
|
||||
ok: true,
|
||||
forwarded: {
|
||||
to: "telegram:123",
|
||||
to: "pollchat:123",
|
||||
pollQuestion: "Lunch?",
|
||||
pollOption: ["Pizza", "Sushi"],
|
||||
pollDurationSeconds: 120,
|
||||
@@ -930,10 +930,10 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
}),
|
||||
);
|
||||
|
||||
const discordPollPlugin = createPollForwardingPlugin({
|
||||
pluginId: "discord",
|
||||
label: "Discord",
|
||||
blurb: "Discord plugin-owned poll test plugin.",
|
||||
const guildPollPlugin = createPollForwardingPlugin({
|
||||
pluginId: "guildchat",
|
||||
label: "Guild Chat",
|
||||
blurb: "Guild chat plugin-owned poll test plugin.",
|
||||
handleAction,
|
||||
});
|
||||
|
||||
@@ -941,9 +941,9 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
setActivePluginRegistry(
|
||||
createTestRegistry([
|
||||
{
|
||||
pluginId: "discord",
|
||||
pluginId: "guildchat",
|
||||
source: "test",
|
||||
plugin: discordPollPlugin,
|
||||
plugin: guildPollPlugin,
|
||||
},
|
||||
]),
|
||||
);
|
||||
@@ -955,18 +955,18 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("lets non-telegram plugins own extra poll fields", async () => {
|
||||
it("lets other plugins own extra poll fields", async () => {
|
||||
const result = await runMessageAction({
|
||||
cfg: {
|
||||
channels: {
|
||||
discord: {
|
||||
guildchat: {
|
||||
token: "tok",
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
action: "poll",
|
||||
params: {
|
||||
channel: "discord",
|
||||
channel: "guildchat",
|
||||
target: "channel:123",
|
||||
pollQuestion: "Lunch?",
|
||||
pollOption: ["Pizza", "Sushi"],
|
||||
@@ -981,7 +981,7 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
expect(handleAction).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
action: "poll",
|
||||
channel: "discord",
|
||||
channel: "guildchat",
|
||||
params: expect.objectContaining({
|
||||
to: "channel:123",
|
||||
pollQuestion: "Lunch?",
|
||||
@@ -1003,13 +1003,13 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
);
|
||||
|
||||
const componentsPlugin: ChannelPlugin = {
|
||||
id: "discord",
|
||||
id: "componentchat",
|
||||
meta: {
|
||||
id: "discord",
|
||||
label: "Discord",
|
||||
selectionLabel: "Discord",
|
||||
docsPath: "/channels/discord",
|
||||
blurb: "Discord components send test plugin.",
|
||||
id: "componentchat",
|
||||
label: "Component Chat",
|
||||
selectionLabel: "Component Chat",
|
||||
docsPath: "/channels/componentchat",
|
||||
blurb: "Component chat send test plugin.",
|
||||
},
|
||||
capabilities: { chatTypes: ["direct"] },
|
||||
config: createAlwaysConfiguredPluginConfig({}),
|
||||
@@ -1024,7 +1024,7 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
setActivePluginRegistry(
|
||||
createTestRegistry([
|
||||
{
|
||||
pluginId: "discord",
|
||||
pluginId: "componentchat",
|
||||
source: "test",
|
||||
plugin: componentsPlugin,
|
||||
},
|
||||
@@ -1047,7 +1047,7 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
cfg: {} as OpenClawConfig,
|
||||
action: "send",
|
||||
params: {
|
||||
channel: "discord",
|
||||
channel: "componentchat",
|
||||
target: "channel:123",
|
||||
message: "hi",
|
||||
components: JSON.stringify(components),
|
||||
@@ -1066,7 +1066,7 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
cfg: {} as OpenClawConfig,
|
||||
action: "send",
|
||||
params: {
|
||||
channel: "discord",
|
||||
channel: "componentchat",
|
||||
target: "channel:123",
|
||||
message: "hi",
|
||||
components: "{not-json}",
|
||||
@@ -1082,13 +1082,13 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
describe("accountId defaults", () => {
|
||||
const handleAction = vi.fn(async () => jsonResult({ ok: true }));
|
||||
const accountPlugin: ChannelPlugin = {
|
||||
id: "discord",
|
||||
id: "accountchat",
|
||||
meta: {
|
||||
id: "discord",
|
||||
label: "Discord",
|
||||
selectionLabel: "Discord",
|
||||
docsPath: "/channels/discord",
|
||||
blurb: "Discord test plugin.",
|
||||
id: "accountchat",
|
||||
label: "Account Chat",
|
||||
selectionLabel: "Account Chat",
|
||||
docsPath: "/channels/accountchat",
|
||||
blurb: "Account chat test plugin.",
|
||||
},
|
||||
capabilities: { chatTypes: ["direct"] },
|
||||
config: {
|
||||
@@ -1105,7 +1105,7 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
setActivePluginRegistry(
|
||||
createTestRegistry([
|
||||
{
|
||||
pluginId: "discord",
|
||||
pluginId: "accountchat",
|
||||
source: "test",
|
||||
plugin: accountPlugin,
|
||||
},
|
||||
@@ -1133,7 +1133,7 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
args: {
|
||||
cfg: {
|
||||
bindings: [
|
||||
{ agentId: "agent-b", match: { channel: "discord", accountId: "account-b" } },
|
||||
{ agentId: "agent-b", match: { channel: "accountchat", accountId: "account-b" } },
|
||||
],
|
||||
} as OpenClawConfig,
|
||||
agentId: "agent-b",
|
||||
@@ -1145,7 +1145,7 @@ describe("runMessageAction plugin dispatch", () => {
|
||||
...args,
|
||||
action: "send",
|
||||
params: {
|
||||
channel: "discord",
|
||||
channel: "accountchat",
|
||||
target: "channel:123",
|
||||
message: "hi",
|
||||
},
|
||||
|
||||
@@ -79,15 +79,14 @@ function buildThreadedChannelRoute(params: {
|
||||
};
|
||||
}
|
||||
|
||||
function parseTelegramTargetForTest(raw: string): {
|
||||
function parseForumTargetForTest(raw: string): {
|
||||
chatId: string;
|
||||
messageThreadId?: number;
|
||||
chatType: "direct" | "group" | "unknown";
|
||||
} {
|
||||
const trimmed = raw
|
||||
.trim()
|
||||
.replace(/^telegram:/i, "")
|
||||
.replace(/^tg:/i, "")
|
||||
.replace(/^forum:/i, "")
|
||||
.replace(/^group:/i, "");
|
||||
const prefixedTopic = /^([^:]+):topic:(\d+)$/i.exec(trimmed);
|
||||
if (prefixedTopic) {
|
||||
@@ -104,7 +103,7 @@ function parseTelegramTargetForTest(raw: string): {
|
||||
};
|
||||
}
|
||||
|
||||
function parseTelegramThreadIdForTest(threadId?: string | number | null): number | undefined {
|
||||
function parseForumThreadIdForTest(threadId?: string | number | null): number | undefined {
|
||||
const normalized = normalizeOutboundThreadId(threadId);
|
||||
if (!normalized) {
|
||||
return undefined;
|
||||
@@ -116,26 +115,24 @@ function parseTelegramThreadIdForTest(threadId?: string | number | null): number
|
||||
return Number.parseInt(topicMatch[1], 10);
|
||||
}
|
||||
|
||||
function buildTelegramGroupPeerIdForTest(chatId: string, messageThreadId?: number): string {
|
||||
function buildForumGroupPeerIdForTest(chatId: string, messageThreadId?: number): string {
|
||||
return messageThreadId ? `${chatId}:topic:${messageThreadId}` : chatId;
|
||||
}
|
||||
|
||||
function resolveTelegramOutboundSessionRouteForTest(params: ChannelOutboundSessionRouteParams) {
|
||||
const parsed = parseTelegramTargetForTest(params.target);
|
||||
function resolveForumOutboundSessionRouteForTest(params: ChannelOutboundSessionRouteParams) {
|
||||
const parsed = parseForumTargetForTest(params.target);
|
||||
const chatId = parsed.chatId.trim();
|
||||
if (!chatId) {
|
||||
return null;
|
||||
}
|
||||
const resolvedThreadId = parsed.messageThreadId ?? parseTelegramThreadIdForTest(params.threadId);
|
||||
const resolvedThreadId = parsed.messageThreadId ?? parseForumThreadIdForTest(params.threadId);
|
||||
const isGroup =
|
||||
parsed.chatType === "group" ||
|
||||
(parsed.chatType === "unknown" &&
|
||||
params.resolvedTarget?.kind !== undefined &&
|
||||
params.resolvedTarget.kind !== "user");
|
||||
const peerId =
|
||||
isGroup && resolvedThreadId
|
||||
? buildTelegramGroupPeerIdForTest(chatId, resolvedThreadId)
|
||||
: chatId;
|
||||
isGroup && resolvedThreadId ? buildForumGroupPeerIdForTest(chatId, resolvedThreadId) : chatId;
|
||||
const peer: RoutePeer = {
|
||||
kind: isGroup ? "group" : "direct",
|
||||
id: peerId,
|
||||
@@ -144,67 +141,71 @@ function resolveTelegramOutboundSessionRouteForTest(params: ChannelOutboundSessi
|
||||
return buildChannelOutboundSessionRoute({
|
||||
cfg: params.cfg,
|
||||
agentId: params.agentId,
|
||||
channel: "telegram",
|
||||
channel: "forum",
|
||||
accountId: params.accountId,
|
||||
peer,
|
||||
chatType: "group",
|
||||
from: `telegram:group:${peerId}`,
|
||||
to: `telegram:${chatId}`,
|
||||
from: `forum:group:${peerId}`,
|
||||
to: `forum:${chatId}`,
|
||||
...(resolvedThreadId !== undefined ? { threadId: resolvedThreadId } : {}),
|
||||
});
|
||||
}
|
||||
return buildThreadedChannelRoute({
|
||||
cfg: params.cfg,
|
||||
agentId: params.agentId,
|
||||
channel: "telegram",
|
||||
channel: "forum",
|
||||
accountId: params.accountId,
|
||||
peer,
|
||||
chatType: "direct",
|
||||
from:
|
||||
resolvedThreadId !== undefined
|
||||
? `telegram:${chatId}:topic:${resolvedThreadId}`
|
||||
: `telegram:${chatId}`,
|
||||
to: `telegram:${chatId}`,
|
||||
? `forum:${chatId}:topic:${resolvedThreadId}`
|
||||
: `forum:${chatId}`,
|
||||
to: `forum:${chatId}`,
|
||||
threadId: resolvedThreadId,
|
||||
});
|
||||
}
|
||||
|
||||
function resolveSlackOutboundSessionRouteForTest(params: ChannelOutboundSessionRouteParams) {
|
||||
function resolveWorkspaceOutboundSessionRouteForTest(params: ChannelOutboundSessionRouteParams) {
|
||||
const trimmed = params.target.trim();
|
||||
if (!trimmed) {
|
||||
return null;
|
||||
}
|
||||
const lower = normalizeLowercaseStringOrEmpty(trimmed);
|
||||
const rawId = stripTargetKindPrefix(stripChannelTargetPrefix(trimmed, "slack"));
|
||||
const rawId = stripTargetKindPrefix(stripChannelTargetPrefix(trimmed, "workspace"));
|
||||
if (!rawId) {
|
||||
return null;
|
||||
}
|
||||
const normalizedId = normalizeLowercaseStringOrEmpty(rawId);
|
||||
const isDm = lower.startsWith("user:") || lower.startsWith("slack:") || /^u/i.test(rawId);
|
||||
const isDm = lower.startsWith("user:") || lower.startsWith("workspace:") || /^u/i.test(rawId);
|
||||
const workspaceConfig = params.cfg.channels?.workspace as
|
||||
| { dm?: { groupChannels?: unknown[] } }
|
||||
| undefined;
|
||||
const isGroupChannel =
|
||||
/^g/i.test(rawId) &&
|
||||
params.cfg.channels?.slack?.dm?.groupChannels?.some(
|
||||
(candidate) => normalizeLowercaseStringOrEmpty(String(candidate)) === normalizedId,
|
||||
) === true;
|
||||
Array.isArray(workspaceConfig?.dm?.groupChannels) &&
|
||||
workspaceConfig.dm.groupChannels.some(
|
||||
(candidate: unknown) => normalizeLowercaseStringOrEmpty(String(candidate)) === normalizedId,
|
||||
);
|
||||
const peerKind: RoutePeer["kind"] = isDm ? "direct" : isGroupChannel ? "group" : "channel";
|
||||
return buildThreadedChannelRoute({
|
||||
cfg: params.cfg,
|
||||
agentId: params.agentId,
|
||||
channel: "slack",
|
||||
channel: "workspace",
|
||||
accountId: params.accountId,
|
||||
peer: { kind: peerKind, id: normalizedId },
|
||||
chatType: peerKind === "direct" ? "direct" : peerKind === "group" ? "group" : "channel",
|
||||
from: isDm
|
||||
? `slack:${rawId}`
|
||||
? `workspace:${rawId}`
|
||||
: isGroupChannel
|
||||
? `slack:group:${rawId}`
|
||||
: `slack:channel:${rawId}`,
|
||||
? `workspace:group:${rawId}`
|
||||
: `workspace:channel:${rawId}`,
|
||||
to: isDm ? `user:${rawId}` : `channel:${rawId}`,
|
||||
threadId: params.replyToId ?? params.threadId ?? undefined,
|
||||
});
|
||||
}
|
||||
|
||||
function resolveDiscordOutboundSessionRouteForTest(params: ChannelOutboundSessionRouteParams) {
|
||||
function resolveGuildChatOutboundSessionRouteForTest(params: ChannelOutboundSessionRouteParams) {
|
||||
const trimmed = params.target.trim();
|
||||
if (!trimmed) {
|
||||
return null;
|
||||
@@ -215,16 +216,16 @@ function resolveDiscordOutboundSessionRouteForTest(params: ChannelOutboundSessio
|
||||
kind = "user";
|
||||
} else if (resolvedKind === "channel" || resolvedKind === "group") {
|
||||
kind = "channel";
|
||||
} else if (/^user:/i.test(trimmed) || /^discord:/i.test(trimmed) || /^<@!?/.test(trimmed)) {
|
||||
} else if (/^user:/i.test(trimmed) || /^guildchat:/i.test(trimmed) || /^<@!?/.test(trimmed)) {
|
||||
kind = "user";
|
||||
} else if (/^channel:/i.test(trimmed)) {
|
||||
kind = "channel";
|
||||
} else if (/^\d+$/u.test(trimmed)) {
|
||||
throw new Error("Ambiguous Discord recipient");
|
||||
throw new Error("Ambiguous Guild Chat recipient");
|
||||
} else {
|
||||
kind = "channel";
|
||||
}
|
||||
const rawId = stripTargetKindPrefix(stripChannelTargetPrefix(trimmed, "discord"));
|
||||
const rawId = stripTargetKindPrefix(stripChannelTargetPrefix(trimmed, "guildchat"));
|
||||
if (!rawId) {
|
||||
return null;
|
||||
}
|
||||
@@ -235,43 +236,43 @@ function resolveDiscordOutboundSessionRouteForTest(params: ChannelOutboundSessio
|
||||
return buildThreadedChannelRoute({
|
||||
cfg: params.cfg,
|
||||
agentId: params.agentId,
|
||||
channel: "discord",
|
||||
channel: "guildchat",
|
||||
accountId: params.accountId,
|
||||
peer,
|
||||
chatType: kind === "user" ? "direct" : "channel",
|
||||
from: kind === "user" ? `discord:${rawId}` : `discord:channel:${rawId}`,
|
||||
from: kind === "user" ? `guildchat:${rawId}` : `guildchat:channel:${rawId}`,
|
||||
to: kind === "user" ? `user:${rawId}` : `channel:${rawId}`,
|
||||
threadId: params.threadId ?? undefined,
|
||||
useSuffix: false,
|
||||
});
|
||||
}
|
||||
|
||||
function resolveMattermostOutboundSessionRouteForTest(params: ChannelOutboundSessionRouteParams) {
|
||||
function resolveBoardChatOutboundSessionRouteForTest(params: ChannelOutboundSessionRouteParams) {
|
||||
const trimmed = params.target.trim();
|
||||
if (!trimmed) {
|
||||
return null;
|
||||
}
|
||||
const isUser = params.resolvedTarget?.kind === "user" || /^user:/i.test(trimmed);
|
||||
const rawId = stripTargetKindPrefix(stripChannelTargetPrefix(trimmed, "mattermost"));
|
||||
const rawId = stripTargetKindPrefix(stripChannelTargetPrefix(trimmed, "boardchat"));
|
||||
if (!rawId) {
|
||||
return null;
|
||||
}
|
||||
return buildThreadedChannelRoute({
|
||||
cfg: params.cfg,
|
||||
agentId: params.agentId,
|
||||
channel: "mattermost",
|
||||
channel: "boardchat",
|
||||
accountId: params.accountId,
|
||||
peer: { kind: isUser ? "direct" : "channel", id: rawId },
|
||||
chatType: isUser ? "direct" : "channel",
|
||||
from: isUser ? `mattermost:${rawId}` : `mattermost:channel:${rawId}`,
|
||||
from: isUser ? `boardchat:${rawId}` : `boardchat:channel:${rawId}`,
|
||||
to: isUser ? `user:${rawId}` : `channel:${rawId}`,
|
||||
threadId: params.replyToId ?? params.threadId ?? undefined,
|
||||
});
|
||||
}
|
||||
|
||||
function resolveWhatsAppOutboundSessionRouteForTest(params: ChannelOutboundSessionRouteParams) {
|
||||
function resolveMobileChatOutboundSessionRouteForTest(params: ChannelOutboundSessionRouteParams) {
|
||||
const normalized = normalizeOptionalLowercaseString(
|
||||
stripChannelTargetPrefix(params.target, "whatsapp"),
|
||||
stripChannelTargetPrefix(params.target, "mobilechat"),
|
||||
);
|
||||
if (!normalized) {
|
||||
return null;
|
||||
@@ -280,7 +281,7 @@ function resolveWhatsAppOutboundSessionRouteForTest(params: ChannelOutboundSessi
|
||||
return buildChannelOutboundSessionRoute({
|
||||
cfg: params.cfg,
|
||||
agentId: params.agentId,
|
||||
channel: "whatsapp",
|
||||
channel: "mobilechat",
|
||||
accountId: params.accountId,
|
||||
peer: { kind: isGroup ? "group" : "direct", id: normalized },
|
||||
chatType: isGroup ? "group" : "direct",
|
||||
@@ -309,8 +310,8 @@ function resolveMatrixOutboundSessionRouteForTest(params: ChannelOutboundSession
|
||||
});
|
||||
}
|
||||
|
||||
function resolveMSTeamsOutboundSessionRouteForTest(params: ChannelOutboundSessionRouteParams) {
|
||||
const trimmed = stripChannelTargetPrefix(params.target, "msteams", "teams");
|
||||
function resolveMeetingChatOutboundSessionRouteForTest(params: ChannelOutboundSessionRouteParams) {
|
||||
const trimmed = stripChannelTargetPrefix(params.target, "meetingchat", "meet");
|
||||
if (!trimmed) {
|
||||
return null;
|
||||
}
|
||||
@@ -326,21 +327,21 @@ function resolveMSTeamsOutboundSessionRouteForTest(params: ChannelOutboundSessio
|
||||
return buildChannelOutboundSessionRoute({
|
||||
cfg: params.cfg,
|
||||
agentId: params.agentId,
|
||||
channel: "msteams",
|
||||
channel: "meetingchat",
|
||||
accountId: params.accountId,
|
||||
peer: { kind: peerKind, id: conversationId },
|
||||
chatType: peerKind,
|
||||
from: isUser
|
||||
? `msteams:${conversationId}`
|
||||
? `meetingchat:${conversationId}`
|
||||
: isChannel
|
||||
? `msteams:channel:${conversationId}`
|
||||
: `msteams:group:${conversationId}`,
|
||||
? `meetingchat:channel:${conversationId}`
|
||||
: `meetingchat:group:${conversationId}`,
|
||||
to: isUser ? `user:${conversationId}` : `conversation:${conversationId}`,
|
||||
});
|
||||
}
|
||||
|
||||
function resolveFeishuOutboundSessionRouteForTest(params: ChannelOutboundSessionRouteParams) {
|
||||
let trimmed = stripChannelTargetPrefix(params.target, "feishu", "lark");
|
||||
function resolveCollabChatOutboundSessionRouteForTest(params: ChannelOutboundSessionRouteParams) {
|
||||
let trimmed = stripChannelTargetPrefix(params.target, "collabchat", "collab");
|
||||
if (!trimmed) {
|
||||
return null;
|
||||
}
|
||||
@@ -360,11 +361,11 @@ function resolveFeishuOutboundSessionRouteForTest(params: ChannelOutboundSession
|
||||
return buildChannelOutboundSessionRoute({
|
||||
cfg: params.cfg,
|
||||
agentId: params.agentId,
|
||||
channel: "feishu",
|
||||
channel: "collabchat",
|
||||
accountId: params.accountId,
|
||||
peer: { kind: isGroup ? "group" : "direct", id: trimmed },
|
||||
chatType: isGroup ? "group" : "direct",
|
||||
from: isGroup ? `feishu:group:${trimmed}` : `feishu:${trimmed}`,
|
||||
from: isGroup ? `collabchat:group:${trimmed}` : `collabchat:${trimmed}`,
|
||||
to: trimmed,
|
||||
});
|
||||
}
|
||||
@@ -390,8 +391,8 @@ function resolveNextcloudTalkOutboundSessionRouteForTest(
|
||||
});
|
||||
}
|
||||
|
||||
function resolveBlueBubblesOutboundSessionRouteForTest(params: ChannelOutboundSessionRouteParams) {
|
||||
const stripped = stripChannelTargetPrefix(params.target, "bluebubbles");
|
||||
function resolveLocalChatOutboundSessionRouteForTest(params: ChannelOutboundSessionRouteParams) {
|
||||
const stripped = stripChannelTargetPrefix(params.target, "localchat");
|
||||
if (!stripped) {
|
||||
return null;
|
||||
}
|
||||
@@ -405,12 +406,12 @@ function resolveBlueBubblesOutboundSessionRouteForTest(params: ChannelOutboundSe
|
||||
return buildChannelOutboundSessionRoute({
|
||||
cfg: params.cfg,
|
||||
agentId: params.agentId,
|
||||
channel: "bluebubbles",
|
||||
channel: "localchat",
|
||||
accountId: params.accountId,
|
||||
peer: { kind: isGroup ? "group" : "direct", id: normalizedId },
|
||||
chatType: isGroup ? "group" : "direct",
|
||||
from: isGroup ? `group:${rawId}` : `bluebubbles:${rawId}`,
|
||||
to: `bluebubbles:${stripped}`,
|
||||
from: isGroup ? `group:${rawId}` : `localchat:${rawId}`,
|
||||
to: `localchat:${stripped}`,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -510,9 +511,9 @@ function resolveTlonOutboundSessionRouteForTest(params: ChannelOutboundSessionRo
|
||||
export function setMinimalOutboundSessionPluginRegistryForTests(): void {
|
||||
const plugins: ChannelPlugin[] = [
|
||||
createSessionRouteTestPlugin({
|
||||
id: "whatsapp",
|
||||
label: "WhatsApp",
|
||||
resolveOutboundSessionRoute: resolveWhatsAppOutboundSessionRouteForTest,
|
||||
id: "mobilechat",
|
||||
label: "Mobile Chat",
|
||||
resolveOutboundSessionRoute: resolveMobileChatOutboundSessionRouteForTest,
|
||||
}),
|
||||
createSessionRouteTestPlugin({
|
||||
id: "matrix",
|
||||
@@ -520,24 +521,24 @@ export function setMinimalOutboundSessionPluginRegistryForTests(): void {
|
||||
resolveOutboundSessionRoute: resolveMatrixOutboundSessionRouteForTest,
|
||||
}),
|
||||
createSessionRouteTestPlugin({
|
||||
id: "msteams",
|
||||
label: "Microsoft Teams",
|
||||
resolveOutboundSessionRoute: resolveMSTeamsOutboundSessionRouteForTest,
|
||||
id: "meetingchat",
|
||||
label: "Meeting Chat",
|
||||
resolveOutboundSessionRoute: resolveMeetingChatOutboundSessionRouteForTest,
|
||||
}),
|
||||
createSessionRouteTestPlugin({
|
||||
id: "slack",
|
||||
label: "Slack",
|
||||
resolveOutboundSessionRoute: resolveSlackOutboundSessionRouteForTest,
|
||||
id: "workspace",
|
||||
label: "Workspace",
|
||||
resolveOutboundSessionRoute: resolveWorkspaceOutboundSessionRouteForTest,
|
||||
}),
|
||||
createSessionRouteTestPlugin({
|
||||
id: "telegram",
|
||||
label: "Telegram",
|
||||
resolveOutboundSessionRoute: resolveTelegramOutboundSessionRouteForTest,
|
||||
id: "forum",
|
||||
label: "Forum",
|
||||
resolveOutboundSessionRoute: resolveForumOutboundSessionRouteForTest,
|
||||
}),
|
||||
createSessionRouteTestPlugin({
|
||||
id: "discord",
|
||||
label: "Discord",
|
||||
resolveOutboundSessionRoute: resolveDiscordOutboundSessionRouteForTest,
|
||||
id: "guildchat",
|
||||
label: "Guild Chat",
|
||||
resolveOutboundSessionRoute: resolveGuildChatOutboundSessionRouteForTest,
|
||||
}),
|
||||
createSessionRouteTestPlugin({
|
||||
id: "nextcloud-talk",
|
||||
@@ -545,9 +546,9 @@ export function setMinimalOutboundSessionPluginRegistryForTests(): void {
|
||||
resolveOutboundSessionRoute: resolveNextcloudTalkOutboundSessionRouteForTest,
|
||||
}),
|
||||
createSessionRouteTestPlugin({
|
||||
id: "bluebubbles",
|
||||
label: "BlueBubbles",
|
||||
resolveOutboundSessionRoute: resolveBlueBubblesOutboundSessionRouteForTest,
|
||||
id: "localchat",
|
||||
label: "Local Chat",
|
||||
resolveOutboundSessionRoute: resolveLocalChatOutboundSessionRouteForTest,
|
||||
}),
|
||||
createSessionRouteTestPlugin({
|
||||
id: "zalo",
|
||||
@@ -570,14 +571,14 @@ export function setMinimalOutboundSessionPluginRegistryForTests(): void {
|
||||
resolveOutboundSessionRoute: resolveTlonOutboundSessionRouteForTest,
|
||||
}),
|
||||
createSessionRouteTestPlugin({
|
||||
id: "feishu",
|
||||
label: "Feishu",
|
||||
resolveOutboundSessionRoute: resolveFeishuOutboundSessionRouteForTest,
|
||||
id: "collabchat",
|
||||
label: "Collab Chat",
|
||||
resolveOutboundSessionRoute: resolveCollabChatOutboundSessionRouteForTest,
|
||||
}),
|
||||
createSessionRouteTestPlugin({
|
||||
id: "mattermost",
|
||||
label: "Mattermost",
|
||||
resolveOutboundSessionRoute: resolveMattermostOutboundSessionRouteForTest,
|
||||
id: "boardchat",
|
||||
label: "Board Chat",
|
||||
resolveOutboundSessionRoute: resolveBoardChatOutboundSessionRouteForTest,
|
||||
}),
|
||||
];
|
||||
setActivePluginRegistry(
|
||||
|
||||
@@ -28,13 +28,13 @@ describe("resolveOutboundSessionRoute", () => {
|
||||
session: {
|
||||
dmScope: "per-peer",
|
||||
identityLinks: {
|
||||
alice: ["discord:123"],
|
||||
alice: ["guildchat:123"],
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
const slackMpimCfg = {
|
||||
const workspaceMpimCfg = {
|
||||
channels: {
|
||||
slack: {
|
||||
workspace: {
|
||||
dm: {
|
||||
groupChannels: ["G123"],
|
||||
},
|
||||
@@ -86,12 +86,12 @@ describe("resolveOutboundSessionRoute", () => {
|
||||
|
||||
it.each([
|
||||
{
|
||||
name: "WhatsApp group jid",
|
||||
name: "MobileChat group jid",
|
||||
cfg: baseConfig,
|
||||
channel: "whatsapp",
|
||||
channel: "mobilechat",
|
||||
target: "120363040000000000@g.us",
|
||||
expected: {
|
||||
sessionKey: "agent:main:whatsapp:group:120363040000000000@g.us",
|
||||
sessionKey: "agent:main:mobilechat:group:120363040000000000@g.us",
|
||||
from: "120363040000000000@g.us",
|
||||
to: "120363040000000000@g.us",
|
||||
chatType: "group",
|
||||
@@ -110,75 +110,75 @@ describe("resolveOutboundSessionRoute", () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "MSTeams conversation target",
|
||||
name: "MeetingChat conversation target",
|
||||
cfg: baseConfig,
|
||||
channel: "msteams",
|
||||
channel: "meetingchat",
|
||||
target: "conversation:19:meeting_abc@thread.tacv2",
|
||||
expected: {
|
||||
sessionKey: "agent:main:msteams:channel:19:meeting_abc@thread.tacv2",
|
||||
from: "msteams:channel:19:meeting_abc@thread.tacv2",
|
||||
sessionKey: "agent:main:meetingchat:channel:19:meeting_abc@thread.tacv2",
|
||||
from: "meetingchat:channel:19:meeting_abc@thread.tacv2",
|
||||
to: "conversation:19:meeting_abc@thread.tacv2",
|
||||
chatType: "channel",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Slack thread",
|
||||
name: "Workspace thread",
|
||||
cfg: baseConfig,
|
||||
channel: "slack",
|
||||
channel: "workspace",
|
||||
target: "channel:C123",
|
||||
replyToId: "456",
|
||||
expected: {
|
||||
sessionKey: "agent:main:slack:channel:c123:thread:456",
|
||||
from: "slack:channel:C123",
|
||||
sessionKey: "agent:main:workspace:channel:c123:thread:456",
|
||||
from: "workspace:channel:C123",
|
||||
to: "channel:C123",
|
||||
threadId: "456",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Telegram topic group",
|
||||
name: "Forum topic group",
|
||||
cfg: baseConfig,
|
||||
channel: "telegram",
|
||||
channel: "forum",
|
||||
target: "-100123456:topic:42",
|
||||
expected: {
|
||||
sessionKey: "agent:main:telegram:group:-100123456:topic:42",
|
||||
from: "telegram:group:-100123456:topic:42",
|
||||
to: "telegram:-100123456",
|
||||
sessionKey: "agent:main:forum:group:-100123456:topic:42",
|
||||
from: "forum:group:-100123456:topic:42",
|
||||
to: "forum:-100123456",
|
||||
threadId: 42,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Telegram DM with topic",
|
||||
name: "Forum DM with topic",
|
||||
cfg: perChannelPeerCfg,
|
||||
channel: "telegram",
|
||||
channel: "forum",
|
||||
target: "123456789:topic:99",
|
||||
expected: {
|
||||
sessionKey: "agent:main:telegram:direct:123456789:thread:99",
|
||||
from: "telegram:123456789:topic:99",
|
||||
to: "telegram:123456789",
|
||||
sessionKey: "agent:main:forum:direct:123456789:thread:99",
|
||||
from: "forum:123456789:topic:99",
|
||||
to: "forum:123456789",
|
||||
threadId: 99,
|
||||
chatType: "direct",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Telegram unresolved username DM",
|
||||
name: "Forum unresolved username DM",
|
||||
cfg: perChannelPeerCfg,
|
||||
channel: "telegram",
|
||||
channel: "forum",
|
||||
target: "@alice",
|
||||
expected: {
|
||||
sessionKey: "agent:main:telegram:direct:@alice",
|
||||
sessionKey: "agent:main:forum:direct:@alice",
|
||||
chatType: "direct",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Telegram DM scoped threadId fallback",
|
||||
name: "Forum DM scoped threadId fallback",
|
||||
cfg: perChannelPeerCfg,
|
||||
channel: "telegram",
|
||||
channel: "forum",
|
||||
target: "12345",
|
||||
threadId: "12345:99",
|
||||
expected: {
|
||||
sessionKey: "agent:main:telegram:direct:12345:thread:99",
|
||||
from: "telegram:12345:topic:99",
|
||||
to: "telegram:12345",
|
||||
sessionKey: "agent:main:forum:direct:12345:thread:99",
|
||||
from: "forum:12345:topic:99",
|
||||
to: "forum:12345",
|
||||
threadId: 99,
|
||||
chatType: "direct",
|
||||
},
|
||||
@@ -186,7 +186,7 @@ describe("resolveOutboundSessionRoute", () => {
|
||||
{
|
||||
name: "identity-links per-peer",
|
||||
cfg: identityLinksCfg,
|
||||
channel: "discord",
|
||||
channel: "guildchat",
|
||||
target: "user:123",
|
||||
expected: {
|
||||
sessionKey: "agent:main:direct:alice",
|
||||
@@ -205,12 +205,12 @@ describe("resolveOutboundSessionRoute", () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "BlueBubbles chat_* prefix stripping",
|
||||
name: "LocalChat chat_* prefix stripping",
|
||||
cfg: baseConfig,
|
||||
channel: "bluebubbles",
|
||||
channel: "localchat",
|
||||
target: "chat_guid:ABC123",
|
||||
expected: {
|
||||
sessionKey: "agent:main:bluebubbles:group:abc123",
|
||||
sessionKey: "agent:main:localchat:group:abc123",
|
||||
from: "group:ABC123",
|
||||
},
|
||||
},
|
||||
@@ -261,71 +261,71 @@ describe("resolveOutboundSessionRoute", () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Slack mpim allowlist -> group key",
|
||||
cfg: slackMpimCfg,
|
||||
channel: "slack",
|
||||
name: "Workspace group allowlist -> group key",
|
||||
cfg: workspaceMpimCfg,
|
||||
channel: "workspace",
|
||||
target: "channel:G123",
|
||||
expected: {
|
||||
sessionKey: "agent:main:slack:group:g123",
|
||||
from: "slack:group:G123",
|
||||
sessionKey: "agent:main:workspace:group:g123",
|
||||
from: "workspace:group:G123",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Feishu explicit group prefix keeps group routing",
|
||||
name: "CollabChat explicit group prefix keeps group routing",
|
||||
cfg: baseConfig,
|
||||
channel: "feishu",
|
||||
channel: "collabchat",
|
||||
target: "group:oc_group_chat",
|
||||
expected: {
|
||||
sessionKey: "agent:main:feishu:group:oc_group_chat",
|
||||
from: "feishu:group:oc_group_chat",
|
||||
sessionKey: "agent:main:collabchat:group:oc_group_chat",
|
||||
from: "collabchat:group:oc_group_chat",
|
||||
to: "oc_group_chat",
|
||||
chatType: "group",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Feishu explicit dm prefix keeps direct routing",
|
||||
name: "CollabChat explicit dm prefix keeps direct routing",
|
||||
cfg: perChannelPeerCfg,
|
||||
channel: "feishu",
|
||||
channel: "collabchat",
|
||||
target: "dm:oc_dm_chat",
|
||||
expected: {
|
||||
sessionKey: "agent:main:feishu:direct:oc_dm_chat",
|
||||
from: "feishu:oc_dm_chat",
|
||||
sessionKey: "agent:main:collabchat:direct:oc_dm_chat",
|
||||
from: "collabchat:oc_dm_chat",
|
||||
to: "oc_dm_chat",
|
||||
chatType: "direct",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Feishu bare oc_ target defaults to direct routing",
|
||||
name: "CollabChat bare oc_ target defaults to direct routing",
|
||||
cfg: perChannelPeerCfg,
|
||||
channel: "feishu",
|
||||
channel: "collabchat",
|
||||
target: "oc_ambiguous_chat",
|
||||
expected: {
|
||||
sessionKey: "agent:main:feishu:direct:oc_ambiguous_chat",
|
||||
from: "feishu:oc_ambiguous_chat",
|
||||
sessionKey: "agent:main:collabchat:direct:oc_ambiguous_chat",
|
||||
from: "collabchat:oc_ambiguous_chat",
|
||||
to: "oc_ambiguous_chat",
|
||||
chatType: "direct",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Slack user DM target",
|
||||
name: "Workspace user DM target",
|
||||
cfg: perChannelPeerCfg,
|
||||
channel: "slack",
|
||||
channel: "workspace",
|
||||
target: "user:U12345ABC",
|
||||
expected: {
|
||||
sessionKey: "agent:main:slack:direct:u12345abc",
|
||||
from: "slack:U12345ABC",
|
||||
sessionKey: "agent:main:workspace:direct:u12345abc",
|
||||
from: "workspace:U12345ABC",
|
||||
to: "user:U12345ABC",
|
||||
chatType: "direct",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Slack channel target without thread",
|
||||
name: "Workspace channel target without thread",
|
||||
cfg: baseConfig,
|
||||
channel: "slack",
|
||||
channel: "workspace",
|
||||
target: "channel:C999XYZ",
|
||||
expected: {
|
||||
sessionKey: "agent:main:slack:channel:c999xyz",
|
||||
from: "slack:channel:C999XYZ",
|
||||
sessionKey: "agent:main:workspace:channel:c999xyz",
|
||||
from: "workspace:channel:C999XYZ",
|
||||
to: "channel:C999XYZ",
|
||||
chatType: "channel",
|
||||
},
|
||||
@@ -336,7 +336,7 @@ describe("resolveOutboundSessionRoute", () => {
|
||||
|
||||
it.each([
|
||||
{
|
||||
name: "uses resolved Discord user targets to route bare numeric ids as DMs",
|
||||
name: "uses resolved GuildChat user targets to route bare numeric ids as DMs",
|
||||
target: "123",
|
||||
resolvedTarget: {
|
||||
to: "user:123",
|
||||
@@ -344,14 +344,14 @@ describe("resolveOutboundSessionRoute", () => {
|
||||
source: "directory" as const,
|
||||
},
|
||||
expected: {
|
||||
sessionKey: "agent:main:discord:direct:123",
|
||||
from: "discord:123",
|
||||
sessionKey: "agent:main:guildchat:direct:123",
|
||||
from: "guildchat:123",
|
||||
to: "user:123",
|
||||
chatType: "direct",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "uses resolved Discord channel targets to route bare numeric ids as channels without thread suffixes",
|
||||
name: "uses resolved GuildChat channel targets to route bare numeric ids as channels without thread suffixes",
|
||||
target: "456",
|
||||
threadId: "789",
|
||||
resolvedTarget: {
|
||||
@@ -360,31 +360,31 @@ describe("resolveOutboundSessionRoute", () => {
|
||||
source: "directory" as const,
|
||||
},
|
||||
expected: {
|
||||
sessionKey: "agent:main:discord:channel:456",
|
||||
baseSessionKey: "agent:main:discord:channel:456",
|
||||
from: "discord:channel:456",
|
||||
sessionKey: "agent:main:guildchat:channel:456",
|
||||
baseSessionKey: "agent:main:guildchat:channel:456",
|
||||
from: "guildchat:channel:456",
|
||||
to: "channel:456",
|
||||
chatType: "channel",
|
||||
threadId: "789",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "uses resolved Mattermost user targets to route bare ids as DMs",
|
||||
name: "uses resolved BoardChat user targets to route bare ids as DMs",
|
||||
target: "dthcxgoxhifn3pwh65cut3ud3w",
|
||||
channel: "mattermost",
|
||||
channel: "boardchat",
|
||||
resolvedTarget: {
|
||||
to: "user:dthcxgoxhifn3pwh65cut3ud3w",
|
||||
kind: "user" as const,
|
||||
source: "directory" as const,
|
||||
},
|
||||
expected: {
|
||||
sessionKey: "agent:main:mattermost:direct:dthcxgoxhifn3pwh65cut3ud3w",
|
||||
from: "mattermost:dthcxgoxhifn3pwh65cut3ud3w",
|
||||
sessionKey: "agent:main:boardchat:direct:dthcxgoxhifn3pwh65cut3ud3w",
|
||||
from: "boardchat:dthcxgoxhifn3pwh65cut3ud3w",
|
||||
to: "user:dthcxgoxhifn3pwh65cut3ud3w",
|
||||
chatType: "direct",
|
||||
},
|
||||
},
|
||||
])("$name", async ({ channel = "discord", target, threadId, resolvedTarget, expected }) => {
|
||||
])("$name", async ({ channel = "guildchat", target, threadId, resolvedTarget, expected }) => {
|
||||
const route = await resolveOutboundSessionRoute({
|
||||
cfg: perChannelPeerSessionCfg,
|
||||
channel,
|
||||
@@ -397,15 +397,15 @@ describe("resolveOutboundSessionRoute", () => {
|
||||
expect(route).toMatchObject(expected);
|
||||
});
|
||||
|
||||
it("rejects bare numeric Discord targets when the caller has no kind hint", async () => {
|
||||
it("rejects bare numeric GuildChat targets when the caller has no kind hint", async () => {
|
||||
await expect(
|
||||
resolveOutboundSessionRoute({
|
||||
cfg: perChannelPeerSessionCfg,
|
||||
channel: "discord",
|
||||
channel: "guildchat",
|
||||
agentId: "main",
|
||||
target: "123",
|
||||
}),
|
||||
).rejects.toThrow(/Ambiguous Discord recipient/);
|
||||
).rejects.toThrow(/Ambiguous Guild Chat recipient/);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -422,13 +422,13 @@ describe("ensureOutboundSessionEntry", () => {
|
||||
store: "/stores/{agentId}.json",
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
channel: "slack",
|
||||
channel: "workspace",
|
||||
route: {
|
||||
sessionKey: "agent:main:slack:channel:c1",
|
||||
baseSessionKey: "agent:work:slack:channel:resolved",
|
||||
sessionKey: "agent:main:workspace:channel:c1",
|
||||
baseSessionKey: "agent:work:workspace:channel:resolved",
|
||||
peer: { kind: "channel", id: "c1" },
|
||||
chatType: "channel",
|
||||
from: "slack:channel:C1",
|
||||
from: "workspace:channel:C1",
|
||||
to: "channel:C1",
|
||||
},
|
||||
});
|
||||
@@ -439,7 +439,7 @@ describe("ensureOutboundSessionEntry", () => {
|
||||
expect(mocks.recordSessionMetaFromInbound).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
storePath: "/stores/main.json",
|
||||
sessionKey: "agent:main:slack:channel:c1",
|
||||
sessionKey: "agent:main:workspace:channel:c1",
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -135,7 +135,7 @@ describe("resolveMessagingTarget (directory fallback)", () => {
|
||||
|
||||
const result = await expectOkResolution({
|
||||
cfg,
|
||||
channel: "mattermost",
|
||||
channel: "workspace",
|
||||
input: "dthcxgoxhifn3pwh65cut3ud3w",
|
||||
});
|
||||
expect(result.target).toEqual({
|
||||
|
||||
Reference in New Issue
Block a user