ARCH: добавить pilot executor MCP discovery
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
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.reason_codes).toContain("pilot_query_documents_mcp_executed");
|
||||
|
||||
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.query_limitations).toContain("MCP fetch failed: timeout");
|
||||
expect(result.reason_codes).toContain("pilot_query_documents_mcp_error");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user