import { beforeEach, describe, expect, it, vi } from "vitest"; import { loadConfig } from "../config/config.js"; import { buildTelegramMessageContextForTest } from "./bot-message-context.test-harness.js"; const { defaultRouteConfig } = vi.hoisted(() => ({ defaultRouteConfig: { agents: { list: [{ id: "main", default: true }, { id: "zu" }, { id: "q" }, { id: "support" }], }, channels: { telegram: {} }, messages: { groupChat: { mentionPatterns: [] } }, }, })); vi.mock("../config/config.js", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, loadConfig: vi.fn(() => defaultRouteConfig), }; }); describe("buildTelegramMessageContext per-topic agentId routing", () => { function buildForumMessage(threadId = 3) { return { message_id: 1, chat: { id: -1001234567890, type: "supergroup" as const, title: "Forum", is_forum: true, }, date: 1700000000, text: "@bot hello", message_thread_id: threadId, from: { id: 42, first_name: "Alice" }, }; } async function buildForumContext(params: { threadId?: number; topicConfig?: Record; }) { return await buildTelegramMessageContextForTest({ message: buildForumMessage(params.threadId), options: { forceWasMentioned: true }, resolveGroupActivation: () => true, resolveTelegramGroupConfig: () => ({ groupConfig: { requireMention: false }, ...(params.topicConfig ? { topicConfig: params.topicConfig } : {}), }), }); } beforeEach(() => { vi.mocked(loadConfig).mockReturnValue(defaultRouteConfig as never); }); it("uses group-level agent when no topic agentId is set", async () => { const ctx = await buildForumContext({ topicConfig: { systemPrompt: "Be nice" } }); expect(ctx).not.toBeNull(); expect(ctx?.ctxPayload?.SessionKey).toBe("agent:main:telegram:group:-1001234567890:topic:3"); }); it("routes to topic-specific agent when agentId is set", async () => { const ctx = await buildForumContext({ topicConfig: { agentId: "zu", systemPrompt: "I am Zu" }, }); expect(ctx).not.toBeNull(); expect(ctx?.ctxPayload?.SessionKey).toContain("agent:zu:"); expect(ctx?.ctxPayload?.SessionKey).toContain("telegram:group:-1001234567890:topic:3"); }); it("different topics route to different agents", async () => { const buildForTopic = async (threadId: number, agentId: string) => await buildForumContext({ threadId, topicConfig: { agentId } }); const ctxA = await buildForTopic(1, "main"); const ctxB = await buildForTopic(3, "zu"); const ctxC = await buildForTopic(5, "q"); expect(ctxA?.ctxPayload?.SessionKey).toContain("agent:main:"); expect(ctxB?.ctxPayload?.SessionKey).toContain("agent:zu:"); expect(ctxC?.ctxPayload?.SessionKey).toContain("agent:q:"); expect(ctxA?.ctxPayload?.SessionKey).not.toBe(ctxB?.ctxPayload?.SessionKey); expect(ctxB?.ctxPayload?.SessionKey).not.toBe(ctxC?.ctxPayload?.SessionKey); }); it("ignores whitespace-only agentId and uses group-level agent", async () => { const ctx = await buildForumContext({ topicConfig: { agentId: " ", systemPrompt: "Be nice" }, }); expect(ctx).not.toBeNull(); expect(ctx?.ctxPayload?.SessionKey).toContain("agent:main:"); }); it("falls back to default agent when topic agentId does not exist", async () => { vi.mocked(loadConfig).mockReturnValue({ agents: { list: [{ id: "main", default: true }, { id: "zu" }], }, channels: { telegram: {} }, messages: { groupChat: { mentionPatterns: [] } }, } as never); const ctx = await buildForumContext({ topicConfig: { agentId: "ghost" } }); expect(ctx).not.toBeNull(); expect(ctx?.ctxPayload?.SessionKey).toContain("agent:main:"); }); it("routes DM topic to specific agent when agentId is set", async () => { const ctx = await buildTelegramMessageContextForTest({ message: { message_id: 1, chat: { id: 123456789, type: "private", }, date: 1700000000, text: "@bot hello", message_thread_id: 99, from: { id: 42, first_name: "Alice" }, }, options: { forceWasMentioned: true }, resolveGroupActivation: () => true, resolveTelegramGroupConfig: () => ({ groupConfig: { requireMention: false }, topicConfig: { agentId: "support", systemPrompt: "I am support" }, }), }); expect(ctx).not.toBeNull(); expect(ctx?.ctxPayload?.SessionKey).toContain("agent:support:"); }); });