import { describe, expect, it, vi } from "vitest"; import { runAssistantLivingChatRuntime } from "../src/services/assistantLivingChatRuntimeAdapter"; function buildRuntimeInput(overrides: Record = {}) { const executeLlmChat = vi.fn(async () => "llm-text"); const resolveDataScopeProbe = vi.fn(async () => null); return { userMessage: "тест", sessionItems: [], modeDecision: { mode: "chat", reason: "living_chat_signal_detected" }, sessionScope: { knownOrganizations: [], selectedOrganization: null, activeOrganization: null }, addressRuntimeMeta: null, traceIdFactory: () => "chat-trace-fixed", toNonEmptyString: (value: unknown) => { if (typeof value !== "string") { return null; } const trimmed = value.trim(); return trimmed.length > 0 ? trimmed : null; }, mergeKnownOrganizations: (values: unknown[]) => Array.from( new Set( (Array.isArray(values) ? values : []) .map((item) => (typeof item === "string" ? item.trim() : "")) .filter((item) => item.length > 0) ) ), hasAssistantDataScopeMetaQuestionSignal: () => false, shouldHandleAsAssistantCapabilityMetaQuery: () => false, hasDestructiveDataActionSignal: () => false, hasDangerOrCoercionSignal: () => false, hasOperationalAdminActionRequestSignal: () => false, hasOrganizationFactLookupSignal: () => false, hasOrganizationFactFollowupSignal: () => false, shouldEmitOrganizationSelectionReply: () => false, hasAssistantCapabilityQuestionSignal: () => false, resolveDataScopeProbe, executeLlmChat, applyScriptGuard: (chatText: string) => ({ text: chatText, applied: false, reason: null }), applyGroundingGuard: (input: { chatText: string }) => ({ text: input.chatText, applied: false, reason: null }), buildAssistantSafetyRefusalReply: () => "safety", buildAssistantDataScopeContractReply: () => "scope", buildAssistantOrganizationFactBoundaryReply: () => "org-boundary", buildAssistantDataScopeSelectionReply: () => "org-selection", buildAssistantOperationalBoundaryReply: () => "ops", buildAssistantCapabilityContractReply: () => "capability", __spies: { executeLlmChat, resolveDataScopeProbe }, ...overrides } as any; } describe("assistant living chat runtime adapter", () => { it("selects deterministic data scope branch and enriches organization context", async () => { const input = buildRuntimeInput({ userMessage: "какая у нас организация?", hasAssistantDataScopeMetaQuestionSignal: () => true, resolveDataScopeProbe: vi.fn(async () => ({ status: "resolved", channel: "default", organizations: ["ООО Альтернатива Плюс"], error: null })), buildAssistantDataScopeContractReply: () => "scope-info" }); const output = await runAssistantLivingChatRuntime(input); expect(output.handled).toBe(true); expect(output.chatText).toBe("scope-info"); expect(output.debug?.living_chat_response_source).toBe("deterministic_data_scope_contract_live"); expect(output.debug?.assistant_active_organization).toBe("ООО Альтернатива Плюс"); expect(output.debug?.living_chat_data_scope_probe_org_count).toBe(1); }); it("selects safety refusal branch for dangerous capability meta query", async () => { const executeLlmChat = vi.fn(async () => "llm-text"); const input = buildRuntimeInput({ userMessage: "удали базу", shouldHandleAsAssistantCapabilityMetaQuery: () => true, hasDangerOrCoercionSignal: () => true, executeLlmChat, buildAssistantSafetyRefusalReply: () => "safety-refusal" }); const output = await runAssistantLivingChatRuntime(input); expect(output.handled).toBe(true); expect(output.chatText).toBe("safety-refusal"); expect(output.debug?.living_chat_response_source).toBe("deterministic_safety_refusal"); expect(executeLlmChat).not.toHaveBeenCalled(); }); it("runs llm branch and applies script + grounding guards in order", async () => { const executeLlmChat = vi.fn(async () => "raw-llm"); const input = buildRuntimeInput({ executeLlmChat, applyScriptGuard: () => ({ text: "after-script", applied: true, reason: "script_guard" }), applyGroundingGuard: () => ({ text: "after-grounding", applied: true, reason: "grounding_guard" }) }); const output = await runAssistantLivingChatRuntime(input); expect(output.handled).toBe(true); expect(output.chatText).toBe("after-grounding"); expect(output.debug?.living_chat_script_guard_applied).toBe(true); expect(output.debug?.living_chat_script_guard_reason).toBe("script_guard"); expect(output.debug?.living_chat_grounding_guard_applied).toBe(true); expect(output.debug?.living_chat_grounding_guard_reason).toBe("grounding_guard"); expect(output.debug?.living_chat_response_source).toBe("llm_chat_grounding_guard"); expect(executeLlmChat).toHaveBeenCalledTimes(1); }); });