NODEDC_1C/llm_normalizer/backend/tests/assistantMcpDiscoveryPilotE...

119 lines
5.2 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, vi } from "vitest";
import { planAssistantMcpDiscovery } from "../src/services/assistantMcpDiscoveryPlanner";
import { executeAssistantMcpDiscoveryPilot } from "../src/services/assistantMcpDiscoveryPilotExecutor";
function buildDeps(rows: Array<Record<string, unknown>>, error: string | null = null) {
return {
executeAddressMcpQuery: vi.fn(async () => ({
fetched_rows: rows.length,
matched_rows: error ? 0 : rows.length,
raw_rows: rows,
rows: error ? [] : rows,
error
}))
};
}
describe("assistant MCP discovery pilot executor", () => {
it("executes only the lifecycle query_documents primitive through injected MCP deps", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "counterparty_lifecycle",
asked_action_family: "activity_duration",
explicit_entity_candidates: ["SVK"]
}
});
const deps = buildDeps([
{ Период: "2020-01-15T00:00:00", Регистратор: "CP_CUSTOMER_ACTIVITY_FIRST", Контрагент: "SVK" },
{ Период: "2023-12-20T00:00:00", Регистратор: "CP_CUSTOMER_ACTIVITY", Контрагент: "SVK" }
]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.pilot_status).toBe("executed");
expect(result.mcp_execution_performed).toBe(true);
expect(result.executed_primitives).toEqual(["query_documents"]);
expect(result.skipped_primitives).toEqual(["resolve_entity_reference", "probe_coverage", "explain_evidence_basis"]);
expect(result.evidence.evidence_status).toBe("confirmed");
expect(result.evidence.confirmed_facts[0]).toContain("SVK");
expect(result.evidence.inferred_facts[0]).toContain("may be inferred");
expect(result.evidence.unknown_facts).toContain("Legal registration date is not proven by this MCP discovery pilot");
expect(result.source_rows_summary).toBe("2 MCP document rows fetched, 2 matched lifecycle scope");
expect(result.derived_activity_period).toEqual({
first_activity_date: "2020-01-15",
latest_activity_date: "2023-12-20",
matched_rows: 2,
duration_total_months: 47,
duration_years: 3,
duration_months_remainder: 11,
duration_human_ru: "3 года 11 месяцев",
inference_basis: "first_and_latest_confirmed_1c_activity_rows"
});
expect(result.reason_codes).toContain("pilot_query_documents_mcp_executed");
expect(result.reason_codes).toContain("pilot_derived_activity_period_from_confirmed_rows");
expect(deps.executeAddressMcpQuery).toHaveBeenCalledTimes(1);
const call = deps.executeAddressMcpQuery.mock.calls[0]?.[0];
expect(String(call?.query ?? "")).toContain("Документ.ПоступлениеНаРасчетныйСчет");
expect(call?.limit).toBeGreaterThan(0);
});
it("does not execute MCP when dry-run still needs clarification", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "counterparty_value",
asked_action_family: "turnover",
explicit_entity_candidates: ["SVK"]
}
});
const deps = buildDeps([]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.pilot_status).toBe("skipped_needs_clarification");
expect(result.mcp_execution_performed).toBe(false);
expect(result.evidence.evidence_status).toBe("insufficient");
expect(deps.executeAddressMcpQuery).not.toHaveBeenCalled();
});
it("keeps non-lifecycle ready plans unsupported until a dedicated pilot exists", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "counterparty_documents",
asked_action_family: "list_documents",
explicit_entity_candidates: ["SVK"]
}
});
const deps = buildDeps([]);
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.pilot_status).toBe("unsupported");
expect(result.mcp_execution_performed).toBe(false);
expect(result.skipped_primitives).toEqual(["resolve_entity_reference", "query_documents", "probe_coverage"]);
expect(result.reason_codes).toContain("pilot_scope_unsupported_for_live_execution");
expect(deps.executeAddressMcpQuery).not.toHaveBeenCalled();
});
it("records MCP errors as limitations without converting them into facts", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {
asked_domain_family: "counterparty_lifecycle",
asked_action_family: "activity_duration",
explicit_entity_candidates: ["SVK"]
}
});
const deps = buildDeps([], "MCP fetch failed: timeout");
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
expect(result.pilot_status).toBe("executed");
expect(result.mcp_execution_performed).toBe(true);
expect(result.evidence.evidence_status).toBe("insufficient");
expect(result.evidence.confirmed_facts).toEqual([]);
expect(result.derived_activity_period).toBeNull();
expect(result.query_limitations).toContain("MCP fetch failed: timeout");
expect(result.reason_codes).toContain("pilot_query_documents_mcp_error");
});
});