168 lines
6.4 KiB
TypeScript
168 lines
6.4 KiB
TypeScript
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");
|
||
});
|
||
});
|