Planner Autonomy: закрепить bounded inference и semantic bridges
This commit is contained in:
@@ -57,6 +57,7 @@ describe("assistant MCP catalog index", () => {
|
||||
const valueFlowTemplate = getAssistantMcpCatalogChainTemplate("value_flow");
|
||||
const valueFlowComparisonTemplate = getAssistantMcpCatalogChainTemplate("value_flow_comparison");
|
||||
const valueFlowRankingTemplate = getAssistantMcpCatalogChainTemplate("value_flow_ranking");
|
||||
const lifecycleTemplate = getAssistantMcpCatalogChainTemplate("lifecycle");
|
||||
|
||||
expect(documentTemplate.fallback_primitives).toEqual([
|
||||
"resolve_entity_reference",
|
||||
@@ -75,6 +76,16 @@ describe("assistant MCP catalog index", () => {
|
||||
"aggregate_by_axis",
|
||||
"probe_coverage"
|
||||
]);
|
||||
expect(lifecycleTemplate.base_required_axes).toEqual([
|
||||
"document_date",
|
||||
"coverage_target",
|
||||
"evidence_basis",
|
||||
"activity_window",
|
||||
"legal_fact_boundary"
|
||||
]);
|
||||
expect(lifecycleTemplate.planning_tags).toEqual(
|
||||
expect.arrayContaining(["bounded_inference", "activity_window", "legal_fact_boundary"])
|
||||
);
|
||||
});
|
||||
|
||||
it("can search reviewed primitives from data-need decomposition candidates", () => {
|
||||
|
||||
@@ -80,10 +80,18 @@ describe("assistant MCP discovery answer adapter", () => {
|
||||
expect(draft.internal_mechanics_allowed).toBe(false);
|
||||
expect(draft.headline).toContain("подтвержденная активность");
|
||||
expect(draft.confirmed_lines[0]).toContain("SVK");
|
||||
expect(draft.confirmed_lines[0]).toContain("matched_rows=1");
|
||||
expect(draft.inference_lines[0]).toContain("меньше месяца");
|
||||
expect(draft.inference_lines.join("\n")).toContain("Первая найденная активность: 2020-01-15");
|
||||
expect(draft.inference_lines.join("\n")).toContain("не юридически подтвержденный возраст регистрации");
|
||||
expect(pilot.evidence.inferred_facts).toContain(
|
||||
"Activity window is bounded by first=2020-01-15, latest=2020-01-15, matched_rows=1"
|
||||
);
|
||||
expect(pilot.evidence.inferred_facts).toContain("Activity-window inference is not legal registration age");
|
||||
expect(draft.unknown_lines).toContain("Legal registration date is not proven by this MCP discovery pilot");
|
||||
expect(draft.unknown_lines).toContain(
|
||||
"Business activity before the first confirmed 1C activity row is not proven by this MCP discovery pilot"
|
||||
);
|
||||
expect(draft.must_not_claim).toContain("Do not present inferred activity duration as a formally confirmed legal fact.");
|
||||
expect(draft.reason_codes).toContain("answer_contains_unknown_fact_boundary");
|
||||
});
|
||||
@@ -912,10 +920,10 @@ describe("assistant MCP discovery answer adapter", () => {
|
||||
const draft = buildAssistantMcpDiscoveryAnswerDraft(pilot);
|
||||
|
||||
expect(draft.inference_lines).toContain(
|
||||
"Requested period coverage was recovered through monthly 1C value-flow probes after the broad probe hit the row limit"
|
||||
"Requested period coverage was recovered through monthly 1C value-flow probes"
|
||||
);
|
||||
expect(draft.unknown_lines).not.toContain(
|
||||
"Complete requested-period coverage is not proven because the MCP discovery probe row limit was reached"
|
||||
"Complete requested-period coverage is not proven by the available checked rows"
|
||||
);
|
||||
});
|
||||
|
||||
@@ -971,6 +979,9 @@ describe("assistant MCP discovery answer adapter", () => {
|
||||
expect(inferenceText).toContain("2020-01-15");
|
||||
expect(inferenceText).toContain("2023-12-20");
|
||||
expect(inferenceText).toContain("не юридически подтвержденный возраст регистрации");
|
||||
expect(pilot.evidence.inferred_facts).toContain(
|
||||
"Activity window is bounded by first=2020-01-15, latest=2023-12-20, matched_rows=2"
|
||||
);
|
||||
expect(draft.reason_codes).toContain("pilot_derived_activity_period_from_confirmed_rows");
|
||||
});
|
||||
|
||||
|
||||
@@ -714,7 +714,7 @@ describe("assistant MCP discovery pilot executor", () => {
|
||||
|
||||
expect(result.derived_value_flow?.coverage_limited_by_probe_limit).toBe(true);
|
||||
expect(result.evidence.unknown_facts).toContain(
|
||||
"Complete requested-period coverage is not proven because the MCP discovery probe row limit was reached"
|
||||
"Complete requested-period coverage is not proven by the available checked rows"
|
||||
);
|
||||
});
|
||||
|
||||
@@ -760,10 +760,10 @@ describe("assistant MCP discovery pilot executor", () => {
|
||||
latest_movement_date: "2020-12-05"
|
||||
});
|
||||
expect(result.evidence.inferred_facts).toContain(
|
||||
"Requested period coverage was recovered through monthly 1C value-flow probes after the broad probe hit the row limit"
|
||||
"Requested period coverage was recovered through monthly 1C value-flow probes"
|
||||
);
|
||||
expect(result.evidence.unknown_facts).not.toContain(
|
||||
"Complete requested-period coverage is not proven because the MCP discovery probe row limit was reached"
|
||||
"Complete requested-period coverage is not proven by the available checked rows"
|
||||
);
|
||||
expect(result.reason_codes).toContain("pilot_monthly_period_chunking_recovered_coverage");
|
||||
});
|
||||
@@ -942,10 +942,10 @@ describe("assistant MCP discovery pilot executor", () => {
|
||||
}
|
||||
});
|
||||
expect(result.evidence.inferred_facts).toContain(
|
||||
"Requested period coverage for bidirectional value-flow was recovered through monthly 1C side probes after a broad probe hit the row limit"
|
||||
"Requested period coverage for bidirectional value-flow was recovered through monthly 1C side probes"
|
||||
);
|
||||
expect(result.evidence.unknown_facts).not.toContain(
|
||||
"Complete requested-period coverage for bidirectional value-flow is not proven because at least one MCP discovery probe row limit was reached"
|
||||
"Complete requested-period coverage for bidirectional value-flow is not proven by the available checked rows"
|
||||
);
|
||||
expect(result.reason_codes).toContain("pilot_bidirectional_outgoing_monthly_period_chunking_recovered_coverage");
|
||||
expect(deps.executeAddressMcpQuery).toHaveBeenCalledTimes(14);
|
||||
|
||||
@@ -671,7 +671,16 @@ describe("assistant MCP discovery planner", () => {
|
||||
"probe_coverage",
|
||||
"explain_evidence_basis"
|
||||
]);
|
||||
expect(result.required_axes).toEqual(["counterparty", "document_date", "coverage_target", "evidence_basis"]);
|
||||
expect(result.required_axes).toEqual([
|
||||
"counterparty",
|
||||
"document_date",
|
||||
"coverage_target",
|
||||
"evidence_basis",
|
||||
"activity_window",
|
||||
"legal_fact_boundary"
|
||||
]);
|
||||
expect(result.reason_codes).toContain("planner_lifecycle_bounded_activity_window_template");
|
||||
expect(result.reason_codes).toContain("planner_lifecycle_legal_fact_boundary_required");
|
||||
});
|
||||
|
||||
it("uses metadata-only planning when the user asks about available schema surface", () => {
|
||||
|
||||
@@ -133,6 +133,68 @@ describe("assistant MCP discovery turn input adapter", () => {
|
||||
expect(result.reason_codes).not.toContain("mcp_discovery_payout_signal_detected");
|
||||
});
|
||||
|
||||
it("overrides a supported exact current-turn payout route when the question asks for a payment amount", () => {
|
||||
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||
userMessage:
|
||||
"\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u044b \u0437\u0430\u043f\u043b\u0430\u0442\u0438\u043b\u0438 \u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a \u0437\u0430 2020 \u0433\u043e\u0434?",
|
||||
effectiveMessage:
|
||||
"\u0421\u043a\u043e\u043b\u044c\u043a\u043e \u0431\u044b\u043b\u043e \u043e\u043f\u043b\u0430\u0447\u0435\u043d\u043e \u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\u0443 '\u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a' \u0432 2020 \u0433\u043e\u0434\u0443?",
|
||||
assistantTurnMeaning: {
|
||||
asked_domain_family: "counterparty",
|
||||
asked_action_family: "counterparty_population_and_roles",
|
||||
explicit_intent_candidate: "counterparty_population_and_roles",
|
||||
explicit_entity_candidates: [{ value: "\u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a" }]
|
||||
},
|
||||
predecomposeContract: {
|
||||
entities: { counterparty: "\u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a" },
|
||||
period: { period_from: "2020-01-01", period_to: "2020-12-31" }
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.adapter_status).toBe("ready");
|
||||
expect(result.should_run_discovery).toBe(true);
|
||||
expect(result.turn_meaning_ref).toMatchObject({
|
||||
asked_domain_family: "counterparty_value",
|
||||
asked_action_family: "payout",
|
||||
explicit_entity_candidates: ["\u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a"],
|
||||
explicit_date_scope: "2020",
|
||||
unsupported_but_understood_family: "counterparty_payouts_or_outflow",
|
||||
stale_replay_forbidden: true
|
||||
});
|
||||
expect(result.reason_codes).toContain("mcp_discovery_current_turn_value_flow_overrides_supported_exact");
|
||||
expect(result.reason_codes).not.toContain("mcp_discovery_not_applicable_for_supported_exact_turn");
|
||||
});
|
||||
|
||||
it("overrides a supported exact current-turn bank list when the question asks for net cash flow", () => {
|
||||
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||
userMessage:
|
||||
"\u043a\u0430\u043a\u043e\u0435 \u043d\u0435\u0442\u0442\u043e \u043f\u043e \u0434\u0435\u043d\u044c\u0433\u0430\u043c \u0441 \u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a \u0437\u0430 2020 \u0433\u043e\u0434: \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u0438 \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u043f\u043b\u0430\u0442\u0438\u043b\u0438?",
|
||||
assistantTurnMeaning: {
|
||||
asked_domain_family: "counterparty",
|
||||
asked_action_family: "bank_operations_by_counterparty",
|
||||
explicit_intent_candidate: "bank_operations_by_counterparty",
|
||||
explicit_entity_candidates: [{ value: "\u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a" }]
|
||||
},
|
||||
predecomposeContract: {
|
||||
entities: { counterparty: "\u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a" },
|
||||
period: { period_from: "2020-01-01", period_to: "2020-12-31" }
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.adapter_status).toBe("ready");
|
||||
expect(result.should_run_discovery).toBe(true);
|
||||
expect(result.turn_meaning_ref).toMatchObject({
|
||||
asked_domain_family: "counterparty_value",
|
||||
asked_action_family: "net_value_flow",
|
||||
explicit_entity_candidates: ["\u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a"],
|
||||
explicit_date_scope: "2020",
|
||||
unsupported_but_understood_family: "counterparty_bidirectional_value_flow_or_netting",
|
||||
stale_replay_forbidden: true
|
||||
});
|
||||
expect(result.reason_codes).toContain("mcp_discovery_current_turn_value_flow_overrides_supported_exact");
|
||||
expect(result.reason_codes).not.toContain("mcp_discovery_not_applicable_for_supported_exact_turn");
|
||||
});
|
||||
|
||||
it("prefers the explicit current-turn counterparty over stale organization-scoped carryover in net follow-up discovery", () => {
|
||||
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||
userMessage: "какое нетто по деньгам с Группа СВК за 2020 год: сколько получили и сколько заплатили?",
|
||||
@@ -1347,6 +1409,26 @@ describe("assistant MCP discovery turn input adapter", () => {
|
||||
expect(result.reason_codes).toContain("mcp_discovery_not_applicable_for_supported_exact_turn");
|
||||
});
|
||||
|
||||
it("does not replace broad business evaluation with metadata discovery", () => {
|
||||
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||
userMessage:
|
||||
"\u041a\u0430\u043a \u0442\u044b \u043e\u0446\u0435\u043d\u0438\u0448\u044c \u0434\u0435\u044f\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438?",
|
||||
assistantTurnMeaning: {
|
||||
asked_domain_family: "business_summary",
|
||||
asked_action_family: "broad_evaluation",
|
||||
explicit_date_scope: "2026-05-01",
|
||||
unsupported_but_understood_family: "broad_business_evaluation",
|
||||
stale_replay_forbidden: true
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.adapter_status).toBe("not_applicable");
|
||||
expect(result.should_run_discovery).toBe(false);
|
||||
expect(result.turn_meaning_ref).toBeNull();
|
||||
expect(result.reason_codes).toContain("mcp_discovery_broad_business_evaluation_kept_in_living_chat");
|
||||
expect(result.reason_codes).toContain("mcp_discovery_not_applicable_for_supported_exact_turn");
|
||||
});
|
||||
|
||||
it("does not bootstrap metadata discovery from a referential document exclusion follow-up over exact document context", () => {
|
||||
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||
userMessage: "кроме этого документа есть еще что-то?",
|
||||
|
||||
Reference in New Issue
Block a user