ARCH: довести planner-selected entity chains и ambiguity follow-up
This commit is contained in:
@@ -316,7 +316,12 @@ describe("assistant MCP discovery answer adapter", () => {
|
||||
expect(draft.answer_mode).toBe("needs_clarification");
|
||||
expect(draft.headline).toContain("несколько похожих контрагентов");
|
||||
expect(draft.inference_lines.join("\n")).toContain("СВК-А");
|
||||
expect(draft.next_step_line).toContain("точное название контрагента");
|
||||
expect(draft.inference_lines.join("\n")).toContain("1. СВК-А");
|
||||
expect(draft.inference_lines.join("\n")).toContain("2. СВК-Б");
|
||||
expect(draft.next_step_line).toContain("какой именно контрагент нужен");
|
||||
expect(draft.next_step_line).toContain("1. СВК-А");
|
||||
expect(draft.next_step_line).toContain("2. СВК-Б");
|
||||
expect(draft.next_step_line).toContain("номером варианта");
|
||||
});
|
||||
|
||||
it.skip("keeps entity search honest when no catalog candidate was confirmed", async () => {
|
||||
|
||||
@@ -249,7 +249,7 @@ describe("assistant MCP discovery pilot executor", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it.skip("executes entity-resolution search through the checked counterparty catalog slice", async () => {
|
||||
it("executes the full entity-resolution chain through the checked counterparty catalog slice", async () => {
|
||||
const planner = planAssistantMcpDiscovery({
|
||||
turnMeaning: {
|
||||
asked_domain_family: "entity_resolution",
|
||||
@@ -268,8 +268,12 @@ describe("assistant MCP discovery pilot executor", () => {
|
||||
expect(result.pilot_status).toBe("executed");
|
||||
expect(result.pilot_scope).toBe("entity_resolution_search_v1");
|
||||
expect(result.mcp_execution_performed).toBe(true);
|
||||
expect(result.executed_primitives).toEqual(["search_business_entity"]);
|
||||
expect(result.skipped_primitives).toEqual(["resolve_entity_reference", "probe_coverage"]);
|
||||
expect(result.executed_primitives).toEqual([
|
||||
"search_business_entity",
|
||||
"resolve_entity_reference",
|
||||
"probe_coverage"
|
||||
]);
|
||||
expect(result.skipped_primitives).toEqual([]);
|
||||
expect(result.derived_entity_resolution).toMatchObject({
|
||||
requested_entity: "Группа СВК",
|
||||
resolution_status: "resolved",
|
||||
@@ -279,20 +283,23 @@ describe("assistant MCP discovery pilot executor", () => {
|
||||
inference_basis: "catalog_counterparty_search_rows"
|
||||
});
|
||||
expect(result.evidence.confirmed_facts).toContain(
|
||||
"A matching 1C counterparty was found in the checked catalog slice: Группа СВК"
|
||||
"В проверенном каталожном срезе 1С найден контрагент: Группа СВК"
|
||||
);
|
||||
expect(result.evidence.inferred_facts).toContain(
|
||||
"Only catalog-level entity grounding was checked so far; no business rows were executed yet"
|
||||
"Пока проверено только заземление сущности по каталогу 1С; документы, движения и денежные показатели еще не проверялись"
|
||||
);
|
||||
expect(result.evidence.unknown_facts).toContain(
|
||||
"No business documents, movements, or turnovers were checked yet; only catalog grounding was attempted"
|
||||
"Документы, движения и денежные показатели по этому контрагенту еще не проверялись; пока был только каталожный поиск"
|
||||
);
|
||||
expect(result.reason_codes).toContain("pilot_search_business_entity_mcp_executed");
|
||||
expect(result.reason_codes).toContain("pilot_resolve_entity_reference_from_catalog_rows");
|
||||
expect(result.reason_codes).toContain("pilot_probe_coverage_executed_for_entity_resolution");
|
||||
expect(result.reason_codes).toContain("pilot_entity_resolution_grounding_stable_for_downstream_probe");
|
||||
expect(result.reason_codes).toContain("pilot_derived_entity_resolution_from_catalog_rows");
|
||||
expect(deps.executeAddressMcpQuery).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it.skip("keeps entity-resolution honest when several catalog candidates remain ambiguous", async () => {
|
||||
it("keeps entity-resolution honest when several catalog candidates remain ambiguous", async () => {
|
||||
const planner = planAssistantMcpDiscovery({
|
||||
turnMeaning: {
|
||||
asked_domain_family: "entity_resolution",
|
||||
@@ -310,6 +317,12 @@ describe("assistant MCP discovery pilot executor", () => {
|
||||
|
||||
expect(result.pilot_status).toBe("executed");
|
||||
expect(result.pilot_scope).toBe("entity_resolution_search_v1");
|
||||
expect(result.executed_primitives).toEqual([
|
||||
"search_business_entity",
|
||||
"resolve_entity_reference",
|
||||
"probe_coverage"
|
||||
]);
|
||||
expect(result.skipped_primitives).toEqual([]);
|
||||
expect(result.derived_entity_resolution).toMatchObject({
|
||||
requested_entity: "СВК",
|
||||
resolution_status: "ambiguous",
|
||||
@@ -319,8 +332,10 @@ describe("assistant MCP discovery pilot executor", () => {
|
||||
});
|
||||
expect(result.evidence.confirmed_facts).toEqual([]);
|
||||
expect(result.evidence.unknown_facts).toContain(
|
||||
"Exact 1C counterparty grounding remains ambiguous across: СВК-А, СВК-Б"
|
||||
"Точное заземление контрагента в 1С остается неоднозначным между вариантами: СВК-А, СВК-Б"
|
||||
);
|
||||
expect(result.reason_codes).toContain("pilot_resolve_entity_reference_requires_clarification");
|
||||
expect(result.reason_codes).toContain("pilot_probe_coverage_executed_for_entity_resolution");
|
||||
expect(result.reason_codes).toContain("pilot_entity_resolution_ambiguity_requires_clarification");
|
||||
});
|
||||
|
||||
|
||||
@@ -281,6 +281,75 @@ describe("assistant MCP discovery response policy", () => {
|
||||
expect(result.reason_codes).not.toContain("mcp_discovery_response_policy_keep_full_confirmed_factual_address_reply");
|
||||
});
|
||||
|
||||
it("keeps runtime-adjusted exact VAT follow-up replies over stale discovery turn meaning", () => {
|
||||
const result = applyAssistantMcpDiscoveryResponsePolicy({
|
||||
currentReply: "Коротко: подтвержденный НДС к уплате за май 2017 — 0,00 руб.",
|
||||
currentReplySource: "address_query_runtime_v1",
|
||||
currentReplyType: "factual",
|
||||
addressRuntimeMeta: {
|
||||
detected_intent: "vat_liability_confirmed_for_tax_period",
|
||||
truth_gate_contract_status: "full_confirmed",
|
||||
assistant_truth_answer_policy_v1: {
|
||||
truth_gate: {
|
||||
coverage_status: "full",
|
||||
grounding_status: "grounded",
|
||||
source_truth_gate_status: "full_confirmed"
|
||||
},
|
||||
answer_shape: {
|
||||
reply_type: "factual",
|
||||
capability_contract_id: "confirmed_vat_liability_for_tax_period"
|
||||
}
|
||||
},
|
||||
assistant_state_transition_v1: {
|
||||
reason_codes: [
|
||||
"root_followup_continue_previous",
|
||||
"intent_adjusted_to_vat_followup_context",
|
||||
"period_from_from_followup_context",
|
||||
"period_to_from_followup_context",
|
||||
"confirmed_balance_exact_vat_tax_period_intent"
|
||||
]
|
||||
},
|
||||
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: "confirmed_snapshot",
|
||||
explicit_entity_candidates: ["ООО Альтернатива Плюс"],
|
||||
explicit_organization_scope: "ООО Альтернатива Плюс",
|
||||
explicit_date_scope: "2017-05-31",
|
||||
unsupported_but_understood_family: "counterparty_value_or_turnover"
|
||||
}
|
||||
},
|
||||
bridge: {
|
||||
bridge_status: "checked_sources_only",
|
||||
user_facing_response_allowed: true,
|
||||
business_fact_answer_allowed: false,
|
||||
requires_user_clarification: false,
|
||||
answer_draft: {
|
||||
answer_mode: "checked_sources_only",
|
||||
headline: "Я проверил доступный контур, но подтвержденного факта для ответа не получил.",
|
||||
confirmed_lines: [],
|
||||
inference_lines: [],
|
||||
unknown_lines: ["Полный объем входящих поступлений вне проверенного периода этим поиском не подтвержден."],
|
||||
limitation_lines: [],
|
||||
next_step_line: null
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.applied).toBe(false);
|
||||
expect(result.decision).toBe("keep_current_reply");
|
||||
expect(result.reply_text).toContain("подтвержденный НДС к уплате");
|
||||
expect(result.reason_codes).toContain(
|
||||
"mcp_discovery_response_policy_keep_runtime_adjusted_exact_reply_over_stale_discovery_turn_meaning"
|
||||
);
|
||||
expect(result.reason_codes).not.toContain("mcp_discovery_response_policy_semantic_conflict_allows_candidate_override");
|
||||
});
|
||||
|
||||
it("keeps address lane answers when discovery was not requested for the current turn", () => {
|
||||
const result = applyAssistantMcpDiscoveryResponsePolicy({
|
||||
currentReply: "supported exact route answer",
|
||||
|
||||
@@ -112,4 +112,132 @@ describe("assistant MCP discovery runtime entry point", () => {
|
||||
expect(result.bridge?.pilot.pilot_scope).toBe("metadata_inspection_v1");
|
||||
expect(result.bridge?.answer_draft.headline).toContain("метаданным 1С");
|
||||
});
|
||||
|
||||
it("runs the bridge for raw entity-resolution wording and executes the full grounding chain", async () => {
|
||||
const result = await runAssistantMcpDiscoveryRuntimeEntryPoint({
|
||||
userMessage: "найди в 1С контрагента Группа СВК",
|
||||
deps: buildDeps([
|
||||
{ Counterparty: "Группа СВК", CounterpartyRef: "Ref-1" },
|
||||
{ Counterparty: "СВК Логистика", CounterpartyRef: "Ref-2" }
|
||||
])
|
||||
});
|
||||
|
||||
expect(result.entry_status).toBe("bridge_executed");
|
||||
expect(result.discovery_attempted).toBe(true);
|
||||
expect(result.turn_input.semantic_data_need).toBe("entity discovery evidence");
|
||||
expect(result.turn_input.turn_meaning_ref).toMatchObject({
|
||||
asked_domain_family: "entity_resolution",
|
||||
asked_action_family: "search_business_entity",
|
||||
explicit_entity_candidates: ["Группа СВК"]
|
||||
});
|
||||
expect(result.bridge?.bridge_status).toBe("answer_draft_ready");
|
||||
expect(result.bridge?.pilot.pilot_scope).toBe("entity_resolution_search_v1");
|
||||
expect(result.bridge?.pilot.executed_primitives).toEqual([
|
||||
"search_business_entity",
|
||||
"resolve_entity_reference",
|
||||
"probe_coverage"
|
||||
]);
|
||||
expect(result.bridge?.pilot.derived_entity_resolution).toMatchObject({
|
||||
resolution_status: "resolved",
|
||||
resolved_entity: "Группа СВК",
|
||||
resolved_reference: "Ref-1"
|
||||
});
|
||||
expect(result.bridge?.answer_draft.answer_mode).toBe("confirmed_with_bounded_inference");
|
||||
});
|
||||
|
||||
it("runs the bridge again when the user clarifies one ambiguous entity-resolution candidate", async () => {
|
||||
const result = await runAssistantMcpDiscoveryRuntimeEntryPoint({
|
||||
userMessage: "СВК-А",
|
||||
followupContext: {
|
||||
previous_discovery_pilot_scope: "entity_resolution_search_v1",
|
||||
previous_discovery_entity_resolution_status: "ambiguous",
|
||||
previous_discovery_entity_candidates: ["СВК", "СВК-А", "СВК-Б"],
|
||||
previous_discovery_entity_ambiguity_candidates: ["СВК-А", "СВК-Б"]
|
||||
},
|
||||
deps: buildDeps([
|
||||
{ Counterparty: "СВК-А", CounterpartyRef: "Ref-1" },
|
||||
{ Counterparty: "СВК-Б", CounterpartyRef: "Ref-2" }
|
||||
])
|
||||
});
|
||||
|
||||
expect(result.entry_status).toBe("bridge_executed");
|
||||
expect(result.discovery_attempted).toBe(true);
|
||||
expect(result.turn_input.source_signal).toBe("followup_context");
|
||||
expect(result.turn_input.semantic_data_need).toBe("entity discovery evidence");
|
||||
expect(result.turn_input.turn_meaning_ref).toMatchObject({
|
||||
asked_domain_family: "entity_resolution",
|
||||
asked_action_family: "search_business_entity",
|
||||
explicit_entity_candidates: ["СВК-А"]
|
||||
});
|
||||
expect(result.bridge?.pilot.pilot_scope).toBe("entity_resolution_search_v1");
|
||||
expect(result.bridge?.pilot.executed_primitives).toEqual([
|
||||
"search_business_entity",
|
||||
"resolve_entity_reference",
|
||||
"probe_coverage"
|
||||
]);
|
||||
expect(result.bridge?.pilot.derived_entity_resolution).toMatchObject({
|
||||
resolution_status: "resolved",
|
||||
resolved_entity: "СВК-А",
|
||||
resolved_reference: "Ref-1"
|
||||
});
|
||||
});
|
||||
|
||||
it("chains an ordinal ambiguity clarification directly into value-flow execution", async () => {
|
||||
const result = await runAssistantMcpDiscoveryRuntimeEntryPoint({
|
||||
userMessage: "второй вариант, сколько получили за 2020 год",
|
||||
followupContext: {
|
||||
previous_discovery_pilot_scope: "entity_resolution_search_v1",
|
||||
previous_discovery_entity_resolution_status: "ambiguous",
|
||||
previous_discovery_entity_candidates: ["СВК", "СВК-А", "СВК-Б"],
|
||||
previous_discovery_entity_ambiguity_candidates: ["СВК-А", "СВК-Б"]
|
||||
},
|
||||
deps: buildDeps([
|
||||
{ Period: "2020-01-15T00:00:00", Amount: 1200, Counterparty: "СВК-Б" },
|
||||
{ Period: "2020-02-20T00:00:00", Amount: 800, Counterparty: "СВК-Б" }
|
||||
])
|
||||
});
|
||||
|
||||
expect(result.entry_status).toBe("bridge_executed");
|
||||
expect(result.discovery_attempted).toBe(true);
|
||||
expect(result.turn_input.source_signal).toBe("followup_context");
|
||||
expect(result.turn_input.semantic_data_need).toBe("counterparty value-flow evidence");
|
||||
expect(result.turn_input.turn_meaning_ref).toMatchObject({
|
||||
asked_domain_family: "counterparty_value",
|
||||
asked_action_family: "turnover",
|
||||
explicit_entity_candidates: ["СВК-Б"],
|
||||
explicit_date_scope: "2020"
|
||||
});
|
||||
expect(result.bridge?.pilot.pilot_scope).toBe("counterparty_value_flow_query_movements_v1");
|
||||
expect(result.bridge?.pilot.derived_value_flow).toMatchObject({
|
||||
counterparty: "СВК-Б",
|
||||
period_scope: "2020",
|
||||
total_amount: 2000
|
||||
});
|
||||
});
|
||||
|
||||
it("chains an ordinal ambiguity clarification directly into document evidence execution", async () => {
|
||||
const result = await runAssistantMcpDiscoveryRuntimeEntryPoint({
|
||||
userMessage: "первый вариант, покажи документы за 2020 год",
|
||||
followupContext: {
|
||||
previous_discovery_pilot_scope: "entity_resolution_search_v1",
|
||||
previous_discovery_entity_resolution_status: "ambiguous",
|
||||
previous_discovery_entity_candidates: ["СВК", "СВК-А", "СВК-Б"],
|
||||
previous_discovery_entity_ambiguity_candidates: ["СВК-А", "СВК-Б"]
|
||||
},
|
||||
deps: buildDeps([{ Period: "2020-03-12T00:00:00", Counterparty: "СВК-А", Registrar: "Doc-1" }])
|
||||
});
|
||||
|
||||
expect(result.entry_status).toBe("bridge_executed");
|
||||
expect(result.discovery_attempted).toBe(true);
|
||||
expect(result.turn_input.source_signal).toBe("followup_context");
|
||||
expect(result.turn_input.semantic_data_need).toBe("document evidence");
|
||||
expect(result.turn_input.turn_meaning_ref).toMatchObject({
|
||||
asked_domain_family: "documents",
|
||||
asked_action_family: "list_documents",
|
||||
explicit_entity_candidates: ["СВК-А"],
|
||||
explicit_date_scope: "2020"
|
||||
});
|
||||
expect(result.bridge?.pilot.pilot_scope).toBe("counterparty_document_evidence_query_documents_v1");
|
||||
expect(result.bridge?.answer_draft.answer_mode).toBe("confirmed_with_bounded_inference");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -261,6 +261,163 @@ describe("assistant MCP discovery turn input adapter", () => {
|
||||
expect(result.reason_codes).toContain("mcp_discovery_counterparty_from_followup_context");
|
||||
});
|
||||
|
||||
it("restarts entity-resolution when the user clarifies one ambiguous candidate", () => {
|
||||
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||
userMessage: "СВК-А",
|
||||
followupContext: {
|
||||
previous_discovery_pilot_scope: "entity_resolution_search_v1",
|
||||
previous_discovery_entity_resolution_status: "ambiguous",
|
||||
previous_discovery_entity_candidates: ["СВК", "СВК-А", "СВК-Б"],
|
||||
previous_discovery_entity_ambiguity_candidates: ["СВК-А", "СВК-Б"]
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.adapter_status).toBe("ready");
|
||||
expect(result.should_run_discovery).toBe(true);
|
||||
expect(result.source_signal).toBe("followup_context");
|
||||
expect(result.semantic_data_need).toBe("entity discovery evidence");
|
||||
expect(result.turn_meaning_ref).toMatchObject({
|
||||
asked_domain_family: "entity_resolution",
|
||||
asked_action_family: "search_business_entity",
|
||||
explicit_entity_candidates: ["СВК-А"],
|
||||
unsupported_but_understood_family: "entity_resolution",
|
||||
stale_replay_forbidden: true
|
||||
});
|
||||
expect(result.reason_codes).toContain("mcp_discovery_entity_resolution_signal_detected");
|
||||
expect(result.reason_codes).toContain("mcp_discovery_entity_resolution_clarification_candidate_selected");
|
||||
});
|
||||
|
||||
it("restarts entity-resolution when the user clarifies an ambiguous candidate by ordinal choice", () => {
|
||||
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||
userMessage: "второй вариант",
|
||||
followupContext: {
|
||||
previous_discovery_pilot_scope: "entity_resolution_search_v1",
|
||||
previous_discovery_entity_resolution_status: "ambiguous",
|
||||
previous_discovery_entity_candidates: ["СВК", "СВК-А", "СВК-Б"],
|
||||
previous_discovery_entity_ambiguity_candidates: ["СВК-А", "СВК-Б"]
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.adapter_status).toBe("ready");
|
||||
expect(result.should_run_discovery).toBe(true);
|
||||
expect(result.source_signal).toBe("followup_context");
|
||||
expect(result.semantic_data_need).toBe("entity discovery evidence");
|
||||
expect(result.turn_meaning_ref).toMatchObject({
|
||||
asked_domain_family: "entity_resolution",
|
||||
asked_action_family: "search_business_entity",
|
||||
explicit_entity_candidates: ["СВК-Б"],
|
||||
unsupported_but_understood_family: "entity_resolution",
|
||||
stale_replay_forbidden: true
|
||||
});
|
||||
expect(result.reason_codes).toContain("mcp_discovery_entity_resolution_clarification_candidate_selected");
|
||||
});
|
||||
|
||||
it("chains an ordinal ambiguity clarification directly into value-flow follow-up intent", () => {
|
||||
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||
userMessage: "второй вариант, сколько получили за 2020 год",
|
||||
followupContext: {
|
||||
previous_discovery_pilot_scope: "entity_resolution_search_v1",
|
||||
previous_discovery_entity_resolution_status: "ambiguous",
|
||||
previous_discovery_entity_candidates: ["СВК", "СВК-А", "СВК-Б"],
|
||||
previous_discovery_entity_ambiguity_candidates: ["СВК-А", "СВК-Б"]
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.adapter_status).toBe("ready");
|
||||
expect(result.should_run_discovery).toBe(true);
|
||||
expect(result.source_signal).toBe("followup_context");
|
||||
expect(result.semantic_data_need).toBe("counterparty value-flow evidence");
|
||||
expect(result.turn_meaning_ref).toMatchObject({
|
||||
asked_domain_family: "counterparty_value",
|
||||
asked_action_family: "turnover",
|
||||
explicit_entity_candidates: ["СВК-Б"],
|
||||
explicit_date_scope: "2020",
|
||||
unsupported_but_understood_family: "counterparty_value_or_turnover",
|
||||
stale_replay_forbidden: true
|
||||
});
|
||||
expect(result.reason_codes).toContain("mcp_discovery_entity_resolution_clarification_candidate_selected");
|
||||
expect(result.reason_codes).toContain("mcp_discovery_value_flow_signal_detected");
|
||||
});
|
||||
|
||||
it("chains an ordinal ambiguity clarification directly into document evidence follow-up intent", () => {
|
||||
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||
userMessage: "второй вариант, покажи документы за 2020 год",
|
||||
followupContext: {
|
||||
previous_discovery_pilot_scope: "entity_resolution_search_v1",
|
||||
previous_discovery_entity_resolution_status: "ambiguous",
|
||||
previous_discovery_entity_candidates: ["СВК", "СВК-А", "СВК-Б"],
|
||||
previous_discovery_entity_ambiguity_candidates: ["СВК-А", "СВК-Б"]
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.adapter_status).toBe("ready");
|
||||
expect(result.should_run_discovery).toBe(true);
|
||||
expect(result.source_signal).toBe("followup_context");
|
||||
expect(result.semantic_data_need).toBe("document evidence");
|
||||
expect(result.turn_meaning_ref).toMatchObject({
|
||||
asked_domain_family: "documents",
|
||||
asked_action_family: "list_documents",
|
||||
explicit_entity_candidates: ["СВК-Б"],
|
||||
explicit_date_scope: "2020",
|
||||
unsupported_but_understood_family: "document_evidence",
|
||||
stale_replay_forbidden: true
|
||||
});
|
||||
expect(result.reason_codes).toContain("mcp_discovery_entity_resolution_clarification_candidate_selected");
|
||||
expect(result.reason_codes).toContain("mcp_discovery_entity_resolution_clarified_document_followup");
|
||||
});
|
||||
|
||||
it("chains an ordinal ambiguity clarification directly into movement evidence follow-up intent", () => {
|
||||
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||
userMessage: "первый вариант, покажи движения за 2020 год",
|
||||
followupContext: {
|
||||
previous_discovery_pilot_scope: "entity_resolution_search_v1",
|
||||
previous_discovery_entity_resolution_status: "ambiguous",
|
||||
previous_discovery_entity_candidates: ["СВК", "СВК-А", "СВК-Б"],
|
||||
previous_discovery_entity_ambiguity_candidates: ["СВК-А", "СВК-Б"]
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.adapter_status).toBe("ready");
|
||||
expect(result.should_run_discovery).toBe(true);
|
||||
expect(result.source_signal).toBe("followup_context");
|
||||
expect(result.semantic_data_need).toBe("movement evidence");
|
||||
expect(result.turn_meaning_ref).toMatchObject({
|
||||
asked_domain_family: "movements",
|
||||
asked_action_family: "list_movements",
|
||||
explicit_entity_candidates: ["СВК-А"],
|
||||
explicit_date_scope: "2020",
|
||||
unsupported_but_understood_family: "movement_evidence",
|
||||
stale_replay_forbidden: true
|
||||
});
|
||||
expect(result.reason_codes).toContain("mcp_discovery_entity_resolution_clarification_candidate_selected");
|
||||
expect(result.reason_codes).toContain("mcp_discovery_entity_resolution_clarified_movement_followup");
|
||||
});
|
||||
|
||||
it("does not silently ground value-flow follow-ups from an ambiguous entity-resolution answer", () => {
|
||||
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||
userMessage: "сколько получили по нему за 2020 год",
|
||||
followupContext: {
|
||||
previous_discovery_pilot_scope: "entity_resolution_search_v1",
|
||||
previous_discovery_entity_resolution_status: "ambiguous",
|
||||
previous_discovery_entity_candidates: ["СВК", "СВК-А", "СВК-Б"],
|
||||
previous_discovery_entity_ambiguity_candidates: ["СВК-А", "СВК-Б"]
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.adapter_status).toBe("ready");
|
||||
expect(result.should_run_discovery).toBe(true);
|
||||
expect(result.semantic_data_need).toBe("counterparty value-flow evidence");
|
||||
expect(result.turn_meaning_ref).toMatchObject({
|
||||
asked_domain_family: "counterparty_value",
|
||||
asked_action_family: "turnover",
|
||||
explicit_date_scope: "2020",
|
||||
unsupported_but_understood_family: "counterparty_value_or_turnover",
|
||||
stale_replay_forbidden: true
|
||||
});
|
||||
expect(result.turn_meaning_ref?.explicit_entity_candidates).toBeUndefined();
|
||||
expect(result.reason_codes).not.toContain("mcp_discovery_grounded_value_flow_followup");
|
||||
});
|
||||
|
||||
it("overrides a wrong exact document intent when a grounded document follow-up asks to switch into movements", () => {
|
||||
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||
userMessage: "а теперь по нему движения за 2020 год",
|
||||
|
||||
@@ -1173,6 +1173,65 @@ describe("assistantTransitionPolicy", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("carries ambiguity candidates from entity-resolution discovery into followup context", () => {
|
||||
const policy = buildPolicy({
|
||||
findLastAddressAssistantItem: () => null,
|
||||
hasAddressFollowupContextSignal: () => true
|
||||
});
|
||||
|
||||
const carryover = policy.resolveAddressFollowupCarryoverContext(
|
||||
"СВК-А",
|
||||
[
|
||||
{
|
||||
role: "assistant",
|
||||
text: "По каталогу 1С нашлось несколько похожих контрагентов: СВК-А, СВК-Б.",
|
||||
debug: {
|
||||
execution_lane: "living_chat",
|
||||
mcp_discovery_response_applied: true,
|
||||
assistant_mcp_discovery_entry_point_v1: {
|
||||
schema_version: "assistant_mcp_discovery_runtime_entry_point_v1",
|
||||
entry_status: "bridge_executed",
|
||||
turn_input: {
|
||||
turn_meaning_ref: {
|
||||
asked_domain_family: "entity_resolution",
|
||||
asked_action_family: "search_business_entity",
|
||||
explicit_entity_candidates: ["СВК"]
|
||||
}
|
||||
},
|
||||
bridge: {
|
||||
bridge_status: "answer_draft_ready",
|
||||
business_fact_answer_allowed: false,
|
||||
pilot: {
|
||||
pilot_scope: "entity_resolution_search_v1",
|
||||
derived_entity_resolution: {
|
||||
requested_entity: "СВК",
|
||||
resolution_status: "ambiguous",
|
||||
resolved_entity: null,
|
||||
ambiguity_candidates: ["СВК-А", "СВК-Б"]
|
||||
}
|
||||
},
|
||||
answer_draft: {
|
||||
answer_mode: "needs_clarification"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
expect(carryover?.followupContext?.previous_discovery_pilot_scope).toBe("entity_resolution_search_v1");
|
||||
expect(carryover?.followupContext?.previous_discovery_entity_resolution_status).toBe("ambiguous");
|
||||
expect(carryover?.followupContext?.previous_discovery_entity_candidates).toEqual(["СВК", "СВК-А", "СВК-Б"]);
|
||||
expect(carryover?.followupContext?.previous_discovery_entity_ambiguity_candidates).toEqual([
|
||||
"СВК-А",
|
||||
"СВК-Б"
|
||||
]);
|
||||
});
|
||||
|
||||
it("keeps exact payout carryover for a short net follow-up without restating counterparty or year", () => {
|
||||
const policy = buildPolicy({
|
||||
findLastAddressAssistantItem: () => ({
|
||||
|
||||
Reference in New Issue
Block a user