import { describe, expect, it } from "vitest"; import { createAssistantBoundaryPolicy } from "../src/services/assistantBoundaryPolicy"; function createPolicy() { return createAssistantBoundaryPolicy({ activeMcpChannel: "default", normalizeOrganizationScopeValue: (value: unknown) => { if (value === null || value === undefined) { return null; } const text = String(value ?? "").trim(); return text.length > 0 ? text : null; }, toNonEmptyString: (value: unknown) => { if (value === null || value === undefined) { return null; } const text = String(value ?? "").trim(); return text.length > 0 ? text : null; }, hasOrganizationFactLookupSignal: (message: string) => /возраст|дата регистрации/i.test(message) }); } describe("assistantBoundaryPolicy", () => { it("builds deterministic data-scope reply for single organization", () => { const policy = createPolicy(); const reply = policy.buildAssistantDataScopeContractReply({ status: "resolved", channel: "finance", organizations: ["ООО Альтернатива Плюс"] }); expect(reply).toContain("MCP-канале `finance`"); expect(reply).toContain("ООО Альтернатива Плюс"); expect(reply.toLowerCase()).toContain("read-only"); }); it("strips unexpected CJK fragments from live chat reply", () => { const policy = createPolicy(); const guarded = policy.applyLivingChatScriptGuard( "Прошу прощения, но я не могу продолжать этот разговор. 随时关注。", "че как" ); expect(guarded.applied).toBe(true); expect(guarded.reason).toBe("unexpected_cjk_fragment_stripped"); expect(guarded.text).toContain("Прошу прощения"); expect(/[\u3400-\u9FFF\uF900-\uFAFF]/u.test(guarded.text)).toBe(false); }); it("blocks ungrounded organization fact answer with deterministic boundary reply", () => { const policy = createPolicy(); const guarded = policy.applyLivingChatGroundingGuard({ userMessage: "какой возраст у альтернативы?", chatText: "Для ООО Альтернатива Плюс дата регистрации 01.07.2015, возраст 8 лет.", organization: "ООО Альтернатива Плюс" }); expect(guarded.applied).toBe(true); expect(guarded.reason).toBe("organization_fact_without_live_source_blocked"); expect(guarded.text.toLowerCase()).toContain("не буду называть"); expect(guarded.text).not.toContain("01.07.2015"); }); });