Planner Autonomy: вынести MCP chain templates в route fabric
This commit is contained in:
@@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest";
|
||||
import { ASSISTANT_MCP_DISCOVERY_PRIMITIVES, buildAssistantMcpDiscoveryPlan } from "../src/services/assistantMcpDiscoveryPolicy";
|
||||
import {
|
||||
buildAssistantMcpCatalogIndex,
|
||||
getAssistantMcpCatalogChainTemplate,
|
||||
getAssistantMcpCatalogPrimitive,
|
||||
reviewAssistantMcpDiscoveryPlanAgainstCatalog,
|
||||
searchAssistantMcpCatalogPrimitivesByDecompositionCandidates,
|
||||
@@ -15,6 +16,7 @@ describe("assistant MCP catalog index", () => {
|
||||
const primitiveIds = index.primitives.map((entry) => entry.primitive_id);
|
||||
|
||||
expect(index.reason_codes).toContain("catalog_covers_all_discovery_primitives");
|
||||
expect(index.reason_codes).toContain("catalog_chain_templates_reference_reviewed_primitives");
|
||||
expect(primitiveIds).toEqual([...ASSISTANT_MCP_DISCOVERY_PRIMITIVES]);
|
||||
for (const entry of index.primitives) {
|
||||
expect(entry.safe_for_model_planning).toBe(true);
|
||||
@@ -26,6 +28,53 @@ describe("assistant MCP catalog index", () => {
|
||||
expect(entry.required_axes_any_of.length).toBeGreaterThan(0);
|
||||
expect(entry.output_fact_kinds.length).toBeGreaterThan(0);
|
||||
}
|
||||
expect(index.chain_templates.map((entry) => entry.chain_id)).toEqual([
|
||||
"metadata_inspection",
|
||||
"catalog_drilldown",
|
||||
"entity_resolution",
|
||||
"document_evidence",
|
||||
"movement_evidence",
|
||||
"value_flow",
|
||||
"value_flow_comparison",
|
||||
"value_flow_ranking",
|
||||
"lifecycle"
|
||||
]);
|
||||
for (const template of index.chain_templates) {
|
||||
expect(template.safe_for_model_planning).toBe(true);
|
||||
expect(template.requires_evidence_gate).toBe(true);
|
||||
expect(template.semantic_data_need.length).toBeGreaterThan(0);
|
||||
expect(template.chain_summary.length).toBeGreaterThan(0);
|
||||
expect(template.fallback_primitives.length).toBeGreaterThan(0);
|
||||
for (const primitive of template.fallback_primitives) {
|
||||
expect(primitiveIds).toContain(primitive);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("exposes reusable chain templates for planner route-fabric selection", () => {
|
||||
const documentTemplate = getAssistantMcpCatalogChainTemplate("document_evidence");
|
||||
const movementTemplate = getAssistantMcpCatalogChainTemplate("movement_evidence");
|
||||
const valueFlowTemplate = getAssistantMcpCatalogChainTemplate("value_flow");
|
||||
const valueFlowComparisonTemplate = getAssistantMcpCatalogChainTemplate("value_flow_comparison");
|
||||
const valueFlowRankingTemplate = getAssistantMcpCatalogChainTemplate("value_flow_ranking");
|
||||
|
||||
expect(documentTemplate.fallback_primitives).toEqual([
|
||||
"resolve_entity_reference",
|
||||
"query_documents",
|
||||
"probe_coverage"
|
||||
]);
|
||||
expect(movementTemplate.fallback_primitives).toEqual([
|
||||
"resolve_entity_reference",
|
||||
"query_movements",
|
||||
"probe_coverage"
|
||||
]);
|
||||
expect(valueFlowTemplate.base_required_axes).toEqual(["aggregate_axis", "amount", "coverage_target"]);
|
||||
expect(valueFlowComparisonTemplate.fallback_primitives).toEqual(["query_movements", "probe_coverage"]);
|
||||
expect(valueFlowRankingTemplate.fallback_primitives).toEqual([
|
||||
"query_movements",
|
||||
"aggregate_by_axis",
|
||||
"probe_coverage"
|
||||
]);
|
||||
});
|
||||
|
||||
it("can search reviewed primitives from data-need decomposition candidates", () => {
|
||||
|
||||
@@ -144,6 +144,7 @@ describe("assistant MCP discovery planner", () => {
|
||||
expect(result.selected_chain_id).toBe("document_evidence");
|
||||
expect(result.proposed_primitives).toEqual(["resolve_entity_reference", "query_documents", "probe_coverage"]);
|
||||
expect(result.reason_codes).toContain("planner_selected_catalog_primitives_from_fact_axis_search");
|
||||
expect(result.reason_codes).toContain("planner_instantiated_catalog_chain_template_document_evidence");
|
||||
expect(result.reason_codes).not.toContain("planner_fell_back_to_recipe_primitives_after_empty_catalog_search");
|
||||
});
|
||||
|
||||
@@ -253,6 +254,7 @@ describe("assistant MCP discovery planner", () => {
|
||||
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");
|
||||
expect(result.reason_codes).toContain("planner_instantiated_catalog_chain_template_movement_evidence");
|
||||
});
|
||||
|
||||
it("filters conflicting document-vs-movement primitives when confirmed metadata surface recommends movements", () => {
|
||||
@@ -412,6 +414,7 @@ describe("assistant MCP discovery planner", () => {
|
||||
expect(result.planner_status).toBe("ready_for_execution");
|
||||
expect(result.selected_chain_id).toBe("entity_resolution");
|
||||
expect(result.reason_codes).toContain("planner_selected_entity_resolution_recipe");
|
||||
expect(result.reason_codes).toContain("planner_instantiated_catalog_chain_template_entity_resolution");
|
||||
expect(result.reason_codes).not.toContain("planner_selected_document_from_confirmed_metadata_surface_ref");
|
||||
expect(result.reason_codes).not.toContain("planner_selected_movement_from_confirmed_metadata_surface_ref");
|
||||
});
|
||||
@@ -464,6 +467,7 @@ describe("assistant MCP discovery planner", () => {
|
||||
"calendar_month"
|
||||
]);
|
||||
expect(result.reason_codes).toContain("planner_selected_monthly_value_flow_from_data_need_graph");
|
||||
expect(result.reason_codes).toContain("planner_instantiated_catalog_chain_template_value_flow");
|
||||
});
|
||||
|
||||
it("does not collapse a ranking-shaped value graph into entity-resolution just because no subject is preselected", () => {
|
||||
@@ -497,6 +501,7 @@ describe("assistant MCP discovery planner", () => {
|
||||
expect(result.required_axes).toEqual(["period", "aggregate_axis", "amount", "coverage_target"]);
|
||||
expect(result.catalog_review.review_status).toBe("needs_more_axes");
|
||||
expect(result.reason_codes).toContain("planner_selected_top_ranked_value_flow_from_data_need_graph");
|
||||
expect(result.reason_codes).toContain("planner_instantiated_catalog_chain_template_value_flow_ranking");
|
||||
expect(result.selected_chain_id).not.toBe("entity_resolution");
|
||||
});
|
||||
|
||||
@@ -532,6 +537,7 @@ describe("assistant MCP discovery planner", () => {
|
||||
expect(result.required_axes).toEqual(["organization", "period", "aggregate_axis", "amount", "coverage_target"]);
|
||||
expect(result.catalog_review.review_status).toBe("catalog_compatible");
|
||||
expect(result.reason_codes).toContain("planner_selected_top_ranked_value_flow_from_data_need_graph");
|
||||
expect(result.reason_codes).toContain("planner_instantiated_catalog_chain_template_value_flow_ranking");
|
||||
});
|
||||
|
||||
it("does not collapse incoming-vs-outgoing comparison into entity-resolution when no counterparty is preselected", () => {
|
||||
@@ -564,6 +570,7 @@ describe("assistant MCP discovery planner", () => {
|
||||
expect(result.proposed_primitives).toEqual(["query_movements", "probe_coverage"]);
|
||||
expect(result.required_axes).toEqual(["period", "amount", "coverage_target"]);
|
||||
expect(result.reason_codes).toContain("planner_selected_bidirectional_value_flow_comparison_from_data_need_graph");
|
||||
expect(result.reason_codes).toContain("planner_instantiated_catalog_chain_template_value_flow_comparison");
|
||||
expect(result.selected_chain_id).not.toBe("entity_resolution");
|
||||
});
|
||||
|
||||
@@ -599,6 +606,7 @@ describe("assistant MCP discovery planner", () => {
|
||||
expect(result.required_axes).toEqual(["organization", "period", "amount", "coverage_target"]);
|
||||
expect(result.catalog_review.review_status).toBe("catalog_compatible");
|
||||
expect(result.reason_codes).toContain("planner_selected_bidirectional_value_flow_comparison_from_data_need_graph");
|
||||
expect(result.reason_codes).toContain("planner_instantiated_catalog_chain_template_value_flow_comparison");
|
||||
});
|
||||
|
||||
it("builds an inference-safe lifecycle plan with evidence explanation", () => {
|
||||
@@ -740,6 +748,7 @@ describe("assistant MCP discovery planner", () => {
|
||||
expect(result.required_axes).toEqual(["organization", "period", "aggregate_axis", "amount", "coverage_target"]);
|
||||
expect(result.catalog_review.review_status).toBe("catalog_compatible");
|
||||
expect(result.reason_codes).toContain("planner_selected_open_scope_value_flow_total_from_data_need_graph");
|
||||
expect(result.reason_codes).toContain("planner_instantiated_catalog_chain_template_value_flow");
|
||||
});
|
||||
it("keeps generic one-sided open totals in organization clarification instead of forcing entity resolution", () => {
|
||||
const result = planAssistantMcpDiscovery({
|
||||
@@ -777,6 +786,7 @@ describe("assistant MCP discovery planner", () => {
|
||||
expect(result.catalog_review.review_status).toBe("needs_more_axes");
|
||||
expect(result.catalog_review.missing_axes_by_primitive.query_movements).toContainEqual(["organization"]);
|
||||
expect(result.reason_codes).toContain("planner_selected_open_scope_value_flow_total_from_data_need_graph");
|
||||
expect(result.reason_codes).toContain("planner_instantiated_catalog_chain_template_value_flow");
|
||||
expect(result.selected_chain_id).not.toBe("entity_resolution");
|
||||
});
|
||||
|
||||
@@ -822,6 +832,7 @@ describe("assistant MCP discovery planner", () => {
|
||||
]);
|
||||
expect(result.catalog_review.review_status).toBe("catalog_compatible");
|
||||
expect(result.reason_codes).toContain("planner_selected_open_scope_value_flow_total_from_data_need_graph");
|
||||
expect(result.reason_codes).toContain("planner_instantiated_catalog_chain_template_value_flow");
|
||||
});
|
||||
|
||||
it("keeps metadata-scoped movement evidence in clarification instead of forcing entity resolution", () => {
|
||||
|
||||
Reference in New Issue
Block a user