import { describe, expect, it } from "vitest"; import { createAssistantLivingModePolicy } from "../src/services/assistantLivingModePolicy"; function buildPolicy() { return createAssistantLivingModePolicy({ featureAssistantLivingChatRouterV1: true, compactWhitespace: (text: string) => text.replace(/\s+/g, " ").trim(), repairAddressMojibake: (text: string) => text, toNonEmptyString: (value: unknown) => { if (value === null || value === undefined) { return null; } const text = String(value).trim(); return text.length > 0 ? text : null; }, normalizeOrganizationScopeValue: (value: unknown) => { if (value === null || value === undefined) { return null; } const text = String(value).trim().replace(/^"+|"+$/g, "").replace(/^'+|'+$/g, ""); return text.length > 0 ? text : null; }, hasReferentialPointer: (text: string) => /(по этому|по тому|это же|этой|этим|этому|этого|этот|эту|этом|это|эти|этих|из этого|из них|из этих|из тех|в этом|тот же|same thing|that one|po etomu|po tomu)/i.test( text.toLowerCase() ), hasSmallTalkSignal: (text: string) => /(привет|как дела|спасибо|благодарю|thanks|thank you|hello|hi)\b/i.test(text.toLowerCase()), hasAssistantCapabilityQuestionSignal: (text: string) => /(?:кто ты|что ты можешь|какие фичи|полный список возможностей|чем ты можешь помочь|что ты умеешь)/i.test(text), hasOperationalAdminActionRequestSignal: (text: string) => /(?:настро|установ|подключ|обнов|почин|исправ|удал|снеси|delete\s+database|drop\s+database)/i.test(text) }); } describe("assistantLivingModePolicy", () => { it("routes data-scope question to chat mode", () => { const policy = buildPolicy(); const decision = policy.resolveLivingAssistantModeDecision({ userMessage: "по какой компании мы можем работать?", addressLaneTriggered: false, useMock: false, predecomposeMode: "unsupported", predecomposeModeConfidence: "low" }); expect(decision.mode).toBe("chat"); expect(decision.reason).toBe("assistant_data_scope_query_detected"); }); it("keeps explicit accounting question in deep mode", () => { const policy = buildPolicy(); const decision = policy.resolveLivingAssistantModeDecision({ userMessage: "покажи документы по сверке за 2020", addressLaneTriggered: false, useMock: false, predecomposeMode: "unsupported", predecomposeModeConfidence: "low" }); expect(decision.mode).toBe("deep_analysis"); expect(decision.reason).toBe("strong_data_signal_detected"); }); it("detects organization fact follow-up after prior boundary reply", () => { const policy = buildPolicy(); const detected = policy.hasOrganizationFactFollowupSignal("давай", [ { role: "assistant", debug: { living_chat_response_source: "deterministic_organization_fact_boundary", living_chat_grounding_guard_reason: null } } ]); expect(detected).toBe(true); }); });