import { describe, expect, it } from "vitest"; import type { RouteHintSummary } from "../src/types/normalizer"; import type { UnifiedRetrievalResult } from "../src/types/assistant"; import { createEmptyInvestigationState } from "../src/services/investigationState"; import { buildAssistantInvestigationStateSnapshot, persistAssistantInvestigationStateSnapshot } from "../src/services/assistantInvestigationStateRuntimeAdapter"; function buildRouteSummary(): RouteHintSummary { return { mode: "deterministic_v2", message_in_scope: true, scope_confidence: "high", planner: { total_fragments: 1, in_scope_fragments: 1, out_of_scope_fragments: 0, discarded_fragments: 0, contains_multiple_tasks: false }, decisions: [ { fragment_id: "F1", domain_relevance: "in_scope", business_scope: "company_specific_accounting", candidate_labels: ["anomaly_probe"], decision_flags: { has_multi_entity_scope: false, asks_for_chain_explanation: false, asks_for_ranking_or_top: false, asks_for_period_summary: false, asks_for_rule_check: true, asks_for_anomaly_scan: true, asks_for_exact_object_trace: false, asks_for_evidence: true, mentions_period_close_context: false }, route: "store_feature_risk", reason: "test-route" } ], fallback: { type: "none", message: null } }; } function buildRetrievalResult(): UnifiedRetrievalResult { return { fragment_id: "F1", requirement_ids: ["R1"], route: "store_feature_risk", status: "ok", result_type: "summary", items: [], summary: {}, evidence: [], why_included: [], selection_reason: [], risk_factors: [], business_interpretation: [], confidence: "medium", limitations: [], errors: [] }; } describe("assistant investigation state runtime adapter", () => { it("returns null and skips persist when feature disabled", () => { const snapshot = buildAssistantInvestigationStateSnapshot({ featureEnabled: false, previousState: createEmptyInvestigationState("asst-1", "2026-04-10T10:00:00.000Z"), timestamp: "2026-04-10T10:01:00.000Z", questionId: "msg-1", userMessage: "проверь 60.01", routeSummary: buildRouteSummary(), requirements: [], coverageReport: { requirements_total: 0, requirements_covered: 0, requirements_uncovered: [], requirements_partially_covered: [], clarification_needed_for: [], out_of_scope_requirements: [] }, retrievalResults: [], replyType: "factual", followupApplied: false }); expect(snapshot).toBeNull(); let persistCalled = false; const persisted = persistAssistantInvestigationStateSnapshot({ featureEnabled: false, sessionId: "asst-1", snapshot: null, persist: () => { persistCalled = true; } }); expect(persisted).toBe(false); expect(persistCalled).toBe(false); }); it("builds snapshot and persists it when feature enabled", () => { const previous = createEmptyInvestigationState("asst-2", "2026-04-10T10:00:00.000Z"); const snapshot = buildAssistantInvestigationStateSnapshot({ featureEnabled: true, previousState: previous, timestamp: "2026-04-10T10:01:00.000Z", questionId: "msg-2", userMessage: "проверь счет 60.01 за 2020-07", routeSummary: buildRouteSummary(), requirements: [ { requirement_id: "R1", source_fragment_id: "F1", requirement_text: "проверить счет 60.01", subject_tokens: ["account_60.01"], status: "covered", route: "store_feature_risk" } ], coverageReport: { requirements_total: 1, requirements_covered: 1, requirements_uncovered: [], requirements_partially_covered: [], clarification_needed_for: [], out_of_scope_requirements: [] }, retrievalResults: [buildRetrievalResult()], replyType: "factual", followupApplied: false }); expect(snapshot).not.toBeNull(); expect(snapshot?.turn_index).toBe(1); expect(snapshot?.question_id).toBe("msg-2"); let persistedSessionId: string | null = null; let persistedQuestionId: string | null = null; const persisted = persistAssistantInvestigationStateSnapshot({ featureEnabled: true, sessionId: "asst-2", snapshot: snapshot, persist: (sessionId, state) => { persistedSessionId = sessionId; persistedQuestionId = state.question_id; } }); expect(persisted).toBe(true); expect(persistedSessionId).toBe("asst-2"); expect(persistedQuestionId).toBe("msg-2"); }); });