Согласовать MCP planner с value-flow цепочками
This commit is contained in:
@@ -829,6 +829,37 @@ describe("assistant MCP discovery pilot executor", () => {
|
||||
expect(deps.executeAddressMcpQuery).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it("preserves explicit date ranges when building bidirectional value-flow probes", async () => {
|
||||
const planner = planAssistantMcpDiscovery({
|
||||
turnMeaning: {
|
||||
asked_domain_family: "counterparty_value",
|
||||
asked_action_family: "net_value_flow",
|
||||
explicit_entity_candidates: ["SVK"],
|
||||
explicit_date_scope: "2020-01-01..2020-12-31",
|
||||
unsupported_but_understood_family: "counterparty_bidirectional_value_flow_or_netting"
|
||||
}
|
||||
});
|
||||
const deps = buildSequentialDeps([
|
||||
{
|
||||
rows: [{ Period: "2020-01-15T00:00:00", Amount: 10000, Counterparty: "SVK" }]
|
||||
},
|
||||
{
|
||||
rows: [{ Period: "2020-03-10T00:00:00", Amount: 4000, Counterparty: "SVK" }]
|
||||
}
|
||||
]);
|
||||
|
||||
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
|
||||
|
||||
expect(result.pilot_status).toBe("executed");
|
||||
expect(result.derived_bidirectional_value_flow?.period_scope).toBe("2020-01-01..2020-12-31");
|
||||
expect(deps.executeAddressMcpQuery).toHaveBeenCalledTimes(2);
|
||||
for (const call of deps.executeAddressMcpQuery.mock.calls) {
|
||||
const query = String(call[0]?.query ?? "");
|
||||
expect(query).toContain("2020, 1, 1");
|
||||
expect(query).toContain("2020, 12, 31");
|
||||
}
|
||||
});
|
||||
|
||||
it("derives monthly bidirectional value-flow breakdown when the turn explicitly asks by month", async () => {
|
||||
const planner = planAssistantMcpDiscovery({
|
||||
turnMeaning: {
|
||||
|
||||
@@ -209,6 +209,48 @@ describe("assistant MCP discovery planner", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("keeps bidirectional value-flow comparison executable when checked totals are derived without aggregate_by_axis", () => {
|
||||
const result = planAssistantMcpDiscovery({
|
||||
dataNeedGraph: {
|
||||
schema_version: "assistant_data_need_graph_v1",
|
||||
policy_owner: "assistantMcpDiscoveryDataNeedGraph",
|
||||
subject_candidates: ["SVK"],
|
||||
business_fact_family: "value_flow",
|
||||
action_family: "net_value_flow",
|
||||
aggregation_need: null,
|
||||
time_scope_need: "explicit_period",
|
||||
comparison_need: "incoming_vs_outgoing",
|
||||
ranking_need: null,
|
||||
proof_expectation: "coverage_checked_fact",
|
||||
clarification_gaps: [],
|
||||
decomposition_candidates: [
|
||||
"resolve_entity_reference",
|
||||
"collect_incoming_movements",
|
||||
"collect_outgoing_movements",
|
||||
"aggregate_checked_amounts",
|
||||
"probe_coverage"
|
||||
],
|
||||
forbidden_overclaim_flags: ["no_raw_model_claims", "no_unchecked_fact_totals"],
|
||||
reason_codes: ["data_need_graph_built", "data_need_graph_comparison_incoming_vs_outgoing"]
|
||||
},
|
||||
turnMeaning: {
|
||||
asked_domain_family: "counterparty_value",
|
||||
asked_action_family: "net_value_flow",
|
||||
explicit_entity_candidates: ["SVK"],
|
||||
explicit_date_scope: "2020"
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.planner_status).toBe("ready_for_execution");
|
||||
expect(result.selected_chain_id).toBe("value_flow_comparison");
|
||||
expect(result.proposed_primitives).toEqual(["resolve_entity_reference", "query_movements", "probe_coverage"]);
|
||||
expect(result.proposed_primitives).not.toContain("aggregate_by_axis");
|
||||
expect(result.required_axes).toEqual(["counterparty", "period", "amount", "coverage_target"]);
|
||||
expect(result.discovery_plan.execution_budget.max_probe_count).toBe(30);
|
||||
expect(result.catalog_review.review_status).toBe("catalog_compatible");
|
||||
expect(result.reason_codes).toContain("planner_selected_bidirectional_value_flow_comparison_from_data_need_graph");
|
||||
});
|
||||
|
||||
it("keeps a value-flow plan in clarification state when period axis is missing", () => {
|
||||
const result = planAssistantMcpDiscovery({
|
||||
turnMeaning: {
|
||||
@@ -537,6 +579,23 @@ describe("assistant MCP discovery planner", () => {
|
||||
|
||||
it("can select catalog drilldown directly from a confirmed catalog metadata surface when the follow-up itself is thin", () => {
|
||||
const result = planAssistantMcpDiscovery({
|
||||
dataNeedGraph: {
|
||||
schema_version: "assistant_data_need_graph_v1",
|
||||
policy_owner: "assistantMcpDiscoveryDataNeedGraph",
|
||||
subject_candidates: ["counterparty"],
|
||||
metadata_scope_hint: "counterparty",
|
||||
business_fact_family: "schema_surface",
|
||||
action_family: "inspect_catalog",
|
||||
aggregation_need: null,
|
||||
time_scope_need: null,
|
||||
comparison_need: null,
|
||||
ranking_need: null,
|
||||
proof_expectation: "schema_surface",
|
||||
clarification_gaps: [],
|
||||
decomposition_candidates: ["inspect_metadata_surface"],
|
||||
forbidden_overclaim_flags: ["no_raw_model_claims", "no_fake_schema_surface"],
|
||||
reason_codes: ["data_need_graph_built", "data_need_graph_family_schema_surface"]
|
||||
},
|
||||
metadataSurface: {
|
||||
selected_entity_set: "Catalog",
|
||||
selected_surface_objects: ["Catalog.Counterparties"],
|
||||
@@ -557,8 +616,17 @@ describe("assistant MCP discovery planner", () => {
|
||||
expect(result.selected_chain_id).toBe("catalog_drilldown");
|
||||
expect(result.proposed_primitives).toEqual(["inspect_1c_metadata"]);
|
||||
expect(result.required_axes).toEqual(["metadata_scope"]);
|
||||
expect(result.catalog_chain_template_matches[0]).toBe("catalog_drilldown");
|
||||
expect(result.catalog_chain_template_alignment).toMatchObject({
|
||||
alignment_status: "selected_matches_top",
|
||||
top_chain_template_match: "catalog_drilldown",
|
||||
selected_chain_template_rank: 1,
|
||||
selected_chain_matches_top: true
|
||||
});
|
||||
expect(result.reason_codes).toContain("planner_selected_catalog_drilldown_from_confirmed_metadata_surface_ref");
|
||||
expect(result.reason_codes).toContain("planner_selected_catalog_primitives_from_metadata_surface_search");
|
||||
expect(result.reason_codes).toContain("planner_catalog_chain_template_promoted_by_confirmed_metadata_surface");
|
||||
expect(result.reason_codes).toContain("planner_catalog_chain_template_search_top_catalog_drilldown");
|
||||
});
|
||||
|
||||
it("scores an explicit document data-need over an ambiguous metadata surface without carrying movement primitives", () => {
|
||||
|
||||
@@ -135,6 +135,43 @@ describe("assistant MCP discovery response policy", () => {
|
||||
expect(result.reason_codes).not.toContain("mcp_discovery_response_policy_not_discovery_ready_address_candidate");
|
||||
});
|
||||
|
||||
it("overrides exact inbound value-flow replies when the discovery turn meaning asks for payouts", () => {
|
||||
const result = applyAssistantMcpDiscoveryResponsePolicy({
|
||||
currentReply: "Incoming turnover by SVK: 12 224 925.00 rub.",
|
||||
currentReplySource: "address_query_runtime_v1",
|
||||
currentReplyType: "factual",
|
||||
addressRuntimeMeta: {
|
||||
detected_intent: "customer_revenue_and_payments",
|
||||
selected_recipe: "address_customer_revenue_and_payments_v1",
|
||||
mcp_call_status: "matched_non_empty",
|
||||
truth_mode: "confirmed",
|
||||
capability_binding_status: "bound",
|
||||
capability_binding_violations: [],
|
||||
assistant_mcp_discovery_entry_point_v1: entryPoint({
|
||||
turn_input: {
|
||||
adapter_status: "ready",
|
||||
should_run_discovery: true,
|
||||
turn_meaning_ref: {
|
||||
asked_domain_family: "counterparty_value",
|
||||
asked_action_family: "payout",
|
||||
explicit_entity_candidates: ["SVK"],
|
||||
explicit_date_scope: "2020"
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.applied).toBe(true);
|
||||
expect(result.decision).toBe("apply_candidate");
|
||||
expect(result.reply_source).toBe("mcp_discovery_response_candidate_guarded");
|
||||
expect(result.reason_codes).toContain("mcp_discovery_response_policy_semantic_conflict_allows_candidate_override");
|
||||
expect(result.reason_codes).toContain(
|
||||
"mcp_discovery_response_policy_value_flow_action_conflict_allows_candidate_override"
|
||||
);
|
||||
expect(result.reason_codes).not.toContain("mcp_discovery_response_policy_keep_exact_matched_factual_address_reply");
|
||||
});
|
||||
|
||||
it("keeps exact matched inventory address replies over stale metadata discovery candidates", () => {
|
||||
const result = applyAssistantMcpDiscoveryResponsePolicy({
|
||||
currentReply: "По товару Шкаф картотечный 1000*400*2100 цепочка поставки и продажи подтверждена.",
|
||||
|
||||
Reference in New Issue
Block a user