ARCH: подключить catalog primitive search к data-need planner

This commit is contained in:
2026-04-22 22:47:22 +03:00
parent 70325dacb6
commit 8b6cd4c329
10 changed files with 364 additions and 53 deletions
@@ -3,7 +3,8 @@ import { ASSISTANT_MCP_DISCOVERY_PRIMITIVES, buildAssistantMcpDiscoveryPlan } fr
import {
buildAssistantMcpCatalogIndex,
getAssistantMcpCatalogPrimitive,
reviewAssistantMcpDiscoveryPlanAgainstCatalog
reviewAssistantMcpDiscoveryPlanAgainstCatalog,
searchAssistantMcpCatalogPrimitivesByDecompositionCandidates
} from "../src/services/assistantMcpCatalogIndex";
describe("assistant MCP catalog index", () => {
@@ -16,11 +17,44 @@ describe("assistant MCP catalog index", () => {
for (const entry of index.primitives) {
expect(entry.safe_for_model_planning).toBe(true);
expect(entry.runtime_must_execute).toBe(true);
expect(entry.decomposition_hints.length).toBeGreaterThan(0);
expect(entry.required_axes_any_of.length).toBeGreaterThan(0);
expect(entry.output_fact_kinds.length).toBeGreaterThan(0);
}
});
it("can search reviewed primitives from data-need decomposition candidates", () => {
const primitives = searchAssistantMcpCatalogPrimitivesByDecompositionCandidates({
decomposition_candidates: [
"resolve_entity_reference",
"collect_scoped_movements",
"aggregate_checked_amounts",
"probe_coverage"
]
});
expect(primitives).toEqual([
"resolve_entity_reference",
"query_movements",
"aggregate_by_axis",
"probe_coverage"
]);
});
it("can suppress aggregate_by_axis for decomposition shapes that derive comparison without an aggregate primitive", () => {
const primitives = searchAssistantMcpCatalogPrimitivesByDecompositionCandidates({
decomposition_candidates: [
"collect_incoming_movements",
"collect_outgoing_movements",
"aggregate_by_month",
"probe_coverage"
],
allow_aggregate_by_axis: false
});
expect(primitives).toEqual(["query_movements", "probe_coverage"]);
});
it("marks a counterparty turnover discovery plan as catalog-compatible when required axes exist", () => {
const plan = buildAssistantMcpDiscoveryPlan({
semanticDataNeed: "counterparty turnover evidence",
@@ -251,7 +251,7 @@ describe("assistant MCP discovery answer adapter", () => {
const draft = buildAssistantMcpDiscoveryAnswerDraft(pilot);
expect(draft.answer_mode).toBe("needs_clarification");
expect(draft.headline).toContain("ranking");
expect(draft.headline).toContain("рейтинг");
expect(draft.next_step_line).toContain("организацию");
expect(draft.next_step_line).not.toContain("Уточните контрагента");
});
@@ -50,6 +50,7 @@ describe("assistant MCP discovery planner", () => {
expect(result.discovery_plan.execution_budget.max_probe_count).toBe(30);
expect(result.reason_codes).toContain("planner_enabled_chunked_coverage_probe_budget");
expect(result.reason_codes).toContain("planner_consumed_data_need_graph_v1");
expect(result.reason_codes).toContain("planner_selected_catalog_primitives_from_decomposition_candidates");
});
it("keeps a value-flow plan in clarification state when period axis is missing", () => {
@@ -147,6 +148,7 @@ describe("assistant MCP discovery planner", () => {
expect(result.proposed_primitives).not.toContain("aggregate_by_axis");
expect(result.required_axes).toEqual(["counterparty", "period", "coverage_target"]);
expect(result.reason_codes).toContain("planner_selected_movement_from_data_need_graph");
expect(result.reason_codes).toContain("planner_selected_catalog_primitives_from_decomposition_candidates");
});
it("can select value-flow chain from data need graph even when turn meaning family is still under-specified", () => {
@@ -105,7 +105,7 @@ describe("assistant MCP discovery runtime bridge", () => {
expect(result.requires_user_clarification).toBe(true);
expect(result.pilot.mcp_execution_performed).toBe(false);
expect(result.planner.selected_chain_id).toBe("value_flow_ranking");
expect(result.answer_draft.headline).toContain("ranking");
expect(result.answer_draft.headline).toContain("рейтинг");
expect(result.answer_draft.next_step_line).toContain("организацию");
expect(result.answer_draft.next_step_line).not.toContain("Уточните контрагента");
});