Files
openclaw/extensions/clickclack/src/inbound.test.ts
T
2026-05-10 17:06:15 +01:00

144 lines
4.4 KiB
TypeScript

import { createPluginRuntimeMock } from "openclaw/plugin-sdk/channel-test-helpers";
import type { PluginRuntime } from "openclaw/plugin-sdk/core";
import { describe, expect, it, vi } from "vitest";
import { handleClickClackInbound } from "./inbound.js";
import { setClickClackRuntime } from "./runtime.js";
import type { CoreConfig, ResolvedClickClackAccount } from "./types.js";
const sendClickClackTextMock = vi.hoisted(() => vi.fn());
type LlmCompleteMock = ReturnType<
typeof vi.fn<
(params: {
agentId?: string;
model?: string;
maxTokens?: number;
purpose?: string;
messages?: unknown[];
}) => Promise<unknown>
>
>;
vi.mock("./outbound.js", () => ({
sendClickClackText: sendClickClackTextMock,
}));
function createRuntime(): PluginRuntime {
return createPluginRuntimeMock({
agent: {
runEmbeddedPiAgent: vi.fn().mockResolvedValue({
payloads: [{ text: "service bot online" }],
meta: {},
}),
},
channel: {
routing: {
resolveAgentRoute({
accountId,
peer,
}: Parameters<PluginRuntime["channel"]["routing"]["resolveAgentRoute"]>[0]) {
return {
agentId: "main",
channel: "clickclack",
accountId: accountId ?? "default",
sessionKey: `agent:main:clickclack:${peer?.kind ?? "channel"}:${peer?.id ?? "general"}`,
mainSessionKey: "agent:main:main",
lastRoutePolicy: "session",
matchedBy: "default",
};
},
buildAgentSessionKey({
agentId,
channel,
accountId,
peer,
}: Parameters<PluginRuntime["channel"]["routing"]["buildAgentSessionKey"]>[0]) {
return `agent:${agentId}:${channel}:${accountId ?? "default"}:${peer?.kind ?? "channel"}:${peer?.id ?? "general"}`;
},
},
},
llm: {
complete: vi.fn().mockResolvedValue({
text: "service bot online",
provider: "openai",
model: "gpt-5.4-mini",
agentId: "service-bot",
usage: {},
audit: {
caller: { kind: "plugin", id: "clickclack" },
},
}),
},
} as unknown as PluginRuntime);
}
describe("handleClickClackInbound", () => {
it("runs model-mode bot accounts without tools and posts the bot reply", async () => {
sendClickClackTextMock.mockReset();
const runtime = createRuntime();
setClickClackRuntime(runtime);
const cfg = {
agents: {
defaults: {
model: "openai/gpt-5.4-mini",
},
},
} satisfies CoreConfig;
const account = {
accountId: "service",
enabled: true,
configured: true,
baseUrl: "http://127.0.0.1:8080",
token: "ccb_service",
workspace: "wsp_1",
agentId: "service-bot",
replyMode: "model",
model: "openai/gpt-5.4-mini",
senderIsOwner: false,
toolsAllow: [],
defaultTo: "channel:general",
allowFrom: ["*"],
reconnectMs: 1_500,
config: {},
} satisfies ResolvedClickClackAccount;
await handleClickClackInbound({
account,
config: cfg,
message: {
id: "msg_1",
workspace_id: "wsp_1",
channel_id: "chn_1",
author_id: "usr_human",
thread_root_id: "msg_1",
body: "hello bot",
body_format: "markdown",
created_at: "2026-05-09T12:00:00.000Z",
author: {
id: "usr_human",
kind: "human",
display_name: "Peter",
handle: "steipete",
avatar_url: "",
created_at: "2026-05-09T12:00:00.000Z",
},
},
});
expect(runtime.channel.turn.runPrepared).not.toHaveBeenCalled();
expect(runtime.agent.runEmbeddedPiAgent).not.toHaveBeenCalled();
const completionRequest = (runtime.llm.complete as LlmCompleteMock).mock.calls[0]?.[0];
expect(completionRequest?.agentId).toBe("service-bot");
expect(completionRequest?.model).toBe("openai/gpt-5.4-mini");
expect(completionRequest?.maxTokens).toBe(96);
expect(completionRequest?.purpose).toBe("clickclack bot reply");
expect(completionRequest?.messages).toEqual([{ role: "user", content: "hello bot" }]);
const sendRequest = sendClickClackTextMock.mock.calls[0]?.[0];
expect(sendRequest?.accountId).toBe("service");
expect(sendRequest?.to).toBe("channel:chn_1");
expect(sendRequest?.text).toBe("service bot online");
expect(sendRequest?.replyToId).toBe("msg_1");
});
});