import assert from "node:assert/strict"; import { createServer } from "node:net"; import { createBotApp } from "../../src/index.js"; import { createMemoryConfigStore } from "../../src/dashboard/config-store.js"; async function readJson(url: string, init?: RequestInit): Promise { const res = await fetch(url, init); assert.equal(res.ok, true, `${init?.method ?? "GET"} ${url} failed with ${res.status}`); return (await res.json()) as unknown; } async function allocateFreePort(): Promise { return await new Promise((resolve, reject) => { const server = createServer(); server.once("error", reject); server.listen(0, "127.0.0.1", () => { const address = server.address(); if (!address || typeof address === "string") { server.close(() => reject(new Error("Failed to allocate free port."))); return; } const { port } = address; server.close((error) => { if (error) { reject(error); return; } resolve(port); }); }); }); } async function run(): Promise { const previousNodeEnv = process.env.NODE_ENV; const previousDashboardPort = process.env.PI_BOT_DASHBOARD_PORT; process.env.NODE_ENV = "production"; process.env.PI_BOT_DASHBOARD_PORT = String(await allocateFreePort()); const configStore = createMemoryConfigStore({ agents: { defaults: { model: { primary: "coze/auto" } } }, models: { providers: { coze: { models: [ { id: "auto", name: "Auto" }, { id: "glm-4.7", name: "GLM-4.7" } ] } } }, channels: { feishu: { enabled: true, requireMention: true, appId: "app-id", thinkingReaction: { enabled: true, emojiType: "SMILE" } }, wechat: { enabled: true, requireMention: false, implementation: "mock" } } }); let app: Awaited> | null = null; try { app = await createBotApp( { appName: "smoke-bot", agent: { mode: "mock" }, routing: { feishuGroupRequireMention: true, wechatGroupRequireMention: false }, channels: { feishu: { enabled: true }, wechat: { enabled: true } } }, { dashboardConfigStore: configStore } ); await app.start(); const dashboardUrl = app.dashboard.getUrl(); const initialModels = (await readJson(`${dashboardUrl}/api/models`)) as { defaultModel: string; options: Array<{ value: string; label: string }>; }; assert.equal(initialModels.defaultModel, "coze/auto"); assert.deepEqual(initialModels.options, [ { value: "coze/auto", label: "coze / Auto" }, { value: "coze/glm-4.7", label: "coze / GLM-4.7" } ]); await readJson(`${dashboardUrl}/api/models`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ models: { defaultModel: "coze/glm-4.7" } }) }); const savedModels = (await readJson(`${dashboardUrl}/api/models`)) as { defaultModel: string }; assert.equal(savedModels.defaultModel, "coze/glm-4.7"); assert.equal( (((configStore.snapshot().agents as { defaults?: { model?: { primary?: string } } }).defaults?.model?.primary) ?? ""), "coze/glm-4.7" ); const initialChannels = (await readJson(`${dashboardUrl}/api/channels`)) as { feishu: { enabled: boolean; thinkingReaction?: { enabled?: boolean; emojiType?: string } }; wechat: { enabled: boolean; implementation?: string }; routing: { feishuGroupRequireMention: boolean; wechatGroupRequireMention: boolean }; }; assert.equal(initialChannels.feishu.enabled, true); assert.equal(initialChannels.feishu.thinkingReaction?.emojiType, "SMILE"); assert.equal(initialChannels.wechat.implementation, "mock"); await readJson(`${dashboardUrl}/api/channels`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ channels: { routing: { feishuGroupRequireMention: false, wechatGroupRequireMention: true }, feishu: { enabled: false, requireMention: false, appId: "updated-app-id", domain: "", encryptKey: "", verificationToken: "", appSecret: "", thinkingReaction: { enabled: false, emojiType: "THINK" } }, wechat: { enabled: true, requireMention: true, implementation: "mock" } } }) }); const savedChannels = (await readJson(`${dashboardUrl}/api/channels`)) as { feishu: { enabled: boolean; appId?: string; thinkingReaction?: { enabled?: boolean; emojiType?: string } }; wechat: { requireMention?: boolean }; }; assert.equal(savedChannels.feishu.enabled, false); assert.equal(savedChannels.feishu.appId, "updated-app-id"); assert.equal(savedChannels.feishu.thinkingReaction?.enabled, false); assert.equal(savedChannels.wechat.requireMention, true); const feishuResult = await app.channels.feishu?.simulateIncomingText({ text: "hello from feishu", senderId: "feishu-user-1", conversationId: "feishu-dm-1", isDirectMessage: true }); assert.ok(feishuResult); assert.equal(feishuResult.handled, true); assert.equal(feishuResult.reply?.text, "mock:feishu:dm:feishu-user-1: hello from feishu"); const duplicateFeishuEvent = { message: { message_id: "feishu-duplicate-1", chat_id: "feishu-dm-duplicate", chat_type: "p2p", content: JSON.stringify({ text: "duplicate hello" }) }, sender: { sender_id: { open_id: "feishu-user-duplicate" } } }; const firstDuplicateResult = await app.channels.feishu?.handleEvent(duplicateFeishuEvent); assert.ok(firstDuplicateResult); assert.equal(firstDuplicateResult.handled, true); const secondDuplicateResult = await app.channels.feishu?.handleEvent(duplicateFeishuEvent); assert.ok(secondDuplicateResult); assert.equal(secondDuplicateResult.handled, false); assert.equal(secondDuplicateResult.reason, "ignored"); const filteredGroupMessage = await app.channels.feishu?.simulateIncomingText({ text: "group message without mention", senderId: "feishu-user-2", conversationId: "feishu-group-1", isDirectMessage: false, mentions: [] }); assert.ok(filteredGroupMessage); assert.equal(filteredGroupMessage.handled, false); const handledGroupMessage = await app.channels.feishu?.simulateIncomingText({ text: "group message with mention", senderId: "feishu-user-2", conversationId: "feishu-group-1", isDirectMessage: false, mentions: [{ id: "bot" }] }); assert.ok(handledGroupMessage); assert.equal(handledGroupMessage.handled, true); const wechatResult = await app.channels.wechat?.simulateIncomingText({ text: "hello from wechat", senderId: "wechat-user-1", conversationId: "wechat-dm-1", isDirectMessage: true }); assert.ok(wechatResult); assert.equal(wechatResult.handled, true); assert.equal(wechatResult.reply?.text, "mock:wechat:group:wechat-dm-1: hello from wechat"); const secondWechatResult = await app.channels.wechat?.simulateIncomingText({ text: "hello again from wechat", senderId: "wechat-user-1", conversationId: "wechat-dm-1", isDirectMessage: true }); assert.ok(secondWechatResult); assert.equal(secondWechatResult.handled, true); assert.equal( secondWechatResult.reply?.text, "mock:wechat:group:wechat-dm-1: hello again from wechat" ); } finally { await app?.stop(); if (previousNodeEnv === undefined) { delete process.env.NODE_ENV; } else { process.env.NODE_ENV = previousNodeEnv; } if (previousDashboardPort === undefined) { delete process.env.PI_BOT_DASHBOARD_PORT; } else { process.env.PI_BOT_DASHBOARD_PORT = previousDashboardPort; } } console.log("smoke test passed"); } run().catch((error: unknown) => { console.error(error); process.exit(1); });