import { describe, expect, it } from "vitest"; import { finalizeAssistantAddressTurn } from "../src/services/assistantAddressTurnFinalizeRuntimeAdapter"; function buildLaneDebug() { return { detected_mode: "address_query", detected_mode_confidence: "high", query_shape: "DOCUMENT_LIST", query_shape_confidence: "high", detected_intent: "list_documents_by_counterparty", detected_intent_confidence: "high", extracted_filters: { counterparty: "свк", limit: 20 }, missing_required_filters: [], selected_recipe: "address_documents_by_counterparty_v1", mcp_call_status_legacy: "matched_non_empty", account_scope_mode: "preferred", account_scope_fallback_applied: false, anchor_type: "counterparty", anchor_value_raw: "свк", anchor_value_resolved: "Группа СВК", resolver_confidence: "medium", ambiguity_count: 0, match_failure_stage: "none", match_failure_reason: null, mcp_call_status: "matched_non_empty", rows_fetched: 20, raw_rows_received: 20, rows_after_account_scope: 5, rows_after_recipe_filter: 3, rows_materialized: 5, rows_matched: 3, raw_row_keys_sample: [], materialization_drop_reason: "none", account_token_raw: null, account_token_normalized: null, account_scope_fields_checked: ["account_dt", "account_kt", "registrator", "analytics"], account_scope_match_strategy: "account_code_regex_plus_alias_map_v1", account_scope_drop_reason: "not_applicable", runtime_readiness: "LIVE_QUERYABLE_WITH_LIMITS", limited_reason_category: null, response_type: "FACTUAL_LIST", limitations: [], reasons: [] } as any; } describe("assistant address turn finalize runtime adapter", () => { it("builds assistant item and passes expected log details into commit runtime", () => { const laneDebug = buildLaneDebug(); const commitCalls: Array> = []; const output = finalizeAssistantAddressTurn({ sessionId: "asst-1", userMessage: "покажи документы по свк", effectiveAddressUserMessage: "документы по контрагенту свк", assistantReply: "Собран список документов.", replyType: "factual", addressLaneDebug: laneDebug, debug: { trace_id: "address-trace-1", x: 1 } as any, carryoverMeta: { previousAddressIntent: "list_documents_by_counterparty", previousAddressAnchor: "Группа СВК" }, llmPreDecomposeMeta: { attempted: true, applied: true, provider: "openai", traceId: "predec-1", reason: "llm_contract_ok", fallbackRuleHit: null, sanitizedUserMessage: "покажи документы по свк", toolGateDecision: "run_address_lane", toolGateReason: "address_mode_classifier_detected", dialogContinuationContract: { decision: "new_topic", target_intent: null }, addressRetryAudit: { attempted: false, reason: null, initial_limited_category: null, retry_result_category: null }, predecomposeContract: { intent: "list_documents_by_counterparty", aggregation_profile: "list_lookup", period: { scope: "year" } } }, appendItem: () => {}, getSession: () => null, persistSession: () => {}, cloneConversation: () => [], logEvent: () => {}, nowIso: () => "2026-04-10T12:00:00.000Z", messageIdFactory: () => "msg-fixed-1", commitFn: ((input: Record) => { commitCalls.push(input); return { currentSession: null, conversation: [] }; }) as any }); expect(output.assistantItem.message_id).toBe("msg-fixed-1"); expect(output.assistantItem.created_at).toBe("2026-04-10T12:00:00.000Z"); expect(output.assistantItem.trace_id).toBe("address-trace-1"); expect(commitCalls).toHaveLength(1); expect(commitCalls[0]?.["eventType"]).toBe("assistant_message_address"); const logDetails = commitCalls[0]?.["logDetails"] as Record; expect(logDetails?.["session_id"]).toBe("asst-1"); expect(logDetails?.["effective_address_user_message"]).toBe("документы по контрагенту свк"); expect(logDetails?.["address_followup_context_applied"]).toBe(true); expect(logDetails?.["address_llm_predecompose_attempted"]).toBe(true); expect(logDetails?.["address_dialog_continuation_decision"]).toBe("new_topic"); expect(logDetails?.["assistant_reply"]).toBe("Собран список документов."); expect(output.response.assistant_reply).toBe("Собран список документов."); expect(output.response.reply_type).toBe("factual"); }); it("uses default commit runtime and returns conversation from stored session", () => { const laneDebug = buildLaneDebug(); let appendCalls = 0; let persistCalls = 0; let logCalls = 0; let storedSession: any = null; const output = finalizeAssistantAddressTurn({ sessionId: "asst-2", userMessage: "покажи документы", effectiveAddressUserMessage: "документы", assistantReply: "Готово", replyType: "partial_coverage", addressLaneDebug: laneDebug, debug: { trace_id: "address-trace-2" } as any, appendItem: (_sessionId, item) => { appendCalls += 1; storedSession = { session_id: "asst-2", updated_at: "2026-04-10T12:00:00.000Z", items: [item], investigation_state: null }; }, getSession: () => storedSession, persistSession: () => { persistCalls += 1; }, cloneConversation: (items) => items.map((item) => ({ ...item })), logEvent: () => { logCalls += 1; }, messageIdFactory: () => "msg-fixed-2", nowIso: () => "2026-04-10T12:10:00.000Z" }); expect(appendCalls).toBe(1); expect(persistCalls).toBe(1); expect(logCalls).toBe(1); expect(output.response.ok).toBe(true); expect(output.response.session_id).toBe("asst-2"); expect(output.response.reply_type).toBe("partial_coverage"); expect(output.response.conversation).toHaveLength(1); expect(output.response.conversation_item.message_id).toBe("msg-fixed-2"); }); });