NODEDC_1C/llm_normalizer/backend/tests/assistantAddressTurnFinaliz...

168 lines
6.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<Record<string, unknown>> = [];
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<string, unknown>) => {
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<string, unknown>;
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");
});
});