Закрепить ответы ассистента по бизнес-зависимостям
This commit is contained in:
@@ -2949,6 +2949,12 @@ describe("address intent resolver expansion (M2.3a)", () => {
|
||||
expect(result.reasons).toContain("unicode_business_overview_supplier_quality_deferred_to_discovery");
|
||||
});
|
||||
|
||||
it("defers supplier dependency follow-up wording to business overview discovery instead of bank ops by pseudo-counterparty", () => {
|
||||
const result = resolveAddressIntent("а по поставщикам и исходящим платежам от кого зависимость?");
|
||||
expect(result.intent).toBe("unknown");
|
||||
expect(result.reasons).toContain("unicode_business_overview_supplier_quality_deferred_to_discovery");
|
||||
});
|
||||
|
||||
it("routes reconciliation mismatch wording into open contracts intent", () => {
|
||||
const result = resolveAddressIntent(
|
||||
"Покажи контрагентов, по которым сальдо скорее всего не совпадет с их актом сверки. Может, стоит поторопиться и запросить сверку?"
|
||||
|
||||
@@ -465,6 +465,64 @@ describe("assistant MCP discovery response candidate", () => {
|
||||
expect(candidate.reply_text).not.toContain("business_overview_route_template_v1");
|
||||
});
|
||||
|
||||
it("formats reviewed supplier dependency answers without duplicated period or punctuation", () => {
|
||||
const candidate = buildAssistantMcpDiscoveryResponseCandidate(
|
||||
entryPoint({
|
||||
turn_input: {
|
||||
adapter_status: "ready",
|
||||
turn_meaning_ref: {
|
||||
asked_domain_family: "business_overview",
|
||||
asked_action_family: "vendor_risk_procurement_boundary",
|
||||
unsupported_but_understood_family: "vendor_risk_procurement_boundary"
|
||||
},
|
||||
data_need_graph: {
|
||||
business_fact_family: "business_overview",
|
||||
ranking_need: null,
|
||||
reason_codes: ["data_need_graph_family_business_overview"]
|
||||
}
|
||||
},
|
||||
bridge: {
|
||||
bridge_status: "answer_draft_ready",
|
||||
user_facing_response_allowed: true,
|
||||
business_fact_answer_allowed: true,
|
||||
requires_user_clarification: false,
|
||||
pilot: {
|
||||
pilot_scope: "business_overview_route_template_v1",
|
||||
derived_business_overview: {
|
||||
vendor_procurement_quality: {
|
||||
period_scope: "за все доступное проверенное окно",
|
||||
total_outgoing_amount_human_ru: "137 963 720,37 руб.",
|
||||
top_outgoing_counterparty: {
|
||||
axis_value: "ГТК-Интер, ООО",
|
||||
total_amount_human_ru: "44 943 460 руб."
|
||||
},
|
||||
top_outgoing_share_pct: 32.58,
|
||||
used_contracts: 291,
|
||||
total_contracts: 394,
|
||||
used_contract_share_pct: 73.86,
|
||||
evidence_status: "reviewed_procurement_concentration"
|
||||
}
|
||||
}
|
||||
},
|
||||
answer_draft: {
|
||||
answer_mode: "confirmed_with_bounded_inference",
|
||||
headline: "Vendor route.",
|
||||
confirmed_lines: [],
|
||||
inference_lines: [],
|
||||
unknown_lines: [],
|
||||
limitation_lines: [],
|
||||
next_step_line: null
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
expect(candidate.reply_text).toContain("ГТК-Интер, ООО держит около 32.58% (44 943 460 руб.)");
|
||||
expect(candidate.reply_text).toContain("Это не аудит поставщиков");
|
||||
expect(candidate.reply_text).not.toContain("за за");
|
||||
expect(candidate.reply_text).not.toContain("руб..");
|
||||
});
|
||||
|
||||
it("uses a compact direct answer for business-overview top year questions", () => {
|
||||
const candidate = buildAssistantMcpDiscoveryResponseCandidate(
|
||||
entryPoint({
|
||||
@@ -1013,6 +1071,67 @@ describe("assistant MCP discovery response candidate", () => {
|
||||
expect(candidate.reply_text).not.toContain("wide overview");
|
||||
});
|
||||
|
||||
it("answers business overview next-check follow-ups with a concrete analyst plan first", () => {
|
||||
const candidate = buildAssistantMcpDiscoveryResponseCandidate(
|
||||
entryPoint({
|
||||
turn_input: {
|
||||
adapter_status: "ready",
|
||||
turn_meaning_ref: {
|
||||
raw_message: "что дальше проверять в первую очередь?",
|
||||
asked_action_family: "broad_evaluation",
|
||||
unsupported_but_understood_family: "broad_business_evaluation",
|
||||
explicit_organization_scope: "ООО Альтернатива Плюс"
|
||||
},
|
||||
data_need_graph: {
|
||||
business_fact_family: "business_overview",
|
||||
ranking_need: null,
|
||||
reason_codes: ["data_need_graph_family_business_overview"]
|
||||
}
|
||||
},
|
||||
bridge: {
|
||||
bridge_status: "answer_draft_ready",
|
||||
user_facing_response_allowed: true,
|
||||
business_fact_answer_allowed: true,
|
||||
requires_user_clarification: false,
|
||||
pilot: {
|
||||
pilot_scope: "business_overview_route_template_v1",
|
||||
derived_business_overview: {
|
||||
incoming_customer_revenue: {
|
||||
total_amount_human_ru: "285 819 547,57 руб.",
|
||||
coverage_limited_by_probe_limit: true
|
||||
},
|
||||
outgoing_supplier_payout: {
|
||||
total_amount_human_ru: "137 963 720,37 руб.",
|
||||
coverage_limited_by_probe_limit: true
|
||||
},
|
||||
net_amount_human_ru: "147 855 827,20 руб.",
|
||||
net_direction: "net_incoming",
|
||||
top_customers: [{ axis_value: "Комитет государственных услуг г. Москвы", total_amount_human_ru: "133 839 880,82 руб." }],
|
||||
top_suppliers: [{ axis_value: "ГТК-Интер, ООО", total_amount_human_ru: "44 943 460 руб." }]
|
||||
}
|
||||
},
|
||||
answer_draft: {
|
||||
answer_mode: "confirmed_with_bounded_inference",
|
||||
headline: "generic advice should not leak",
|
||||
confirmed_lines: [],
|
||||
inference_lines: [],
|
||||
unknown_lines: [],
|
||||
limitation_lines: [],
|
||||
next_step_line: null
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
const firstLine = candidate.reply_text?.split("\n")[0] ?? "";
|
||||
expect(firstLine).toContain("чистую прибыль через закрытие 90/91/99");
|
||||
expect(firstLine).toContain("топ-3");
|
||||
expect(firstLine).toContain("долги");
|
||||
expect(firstLine).toContain("складские остатки");
|
||||
expect(candidate.reply_text).toContain("не считаю полным бухгалтерским оборотом");
|
||||
expect(candidate.reply_text).not.toContain("generic advice");
|
||||
});
|
||||
|
||||
it("keeps counterparty leaders for money followups instead of compact cashflow", () => {
|
||||
const candidate = buildAssistantMcpDiscoveryResponseCandidate(
|
||||
entryPoint({
|
||||
|
||||
@@ -2637,6 +2637,70 @@ describe("assistant MCP discovery turn input adapter", () => {
|
||||
expect(result.data_need_graph?.clarification_gaps).toEqual([]);
|
||||
});
|
||||
|
||||
it("keeps supplier dependency follow-ups in business overview instead of pseudo-counterparty bank operations", () => {
|
||||
const orgName = "ООО Альтернатива Плюс";
|
||||
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||
userMessage: "а по поставщикам и исходящим платежам от кого зависимость?",
|
||||
assistantTurnMeaning: {
|
||||
asked_domain_family: "counterparty",
|
||||
asked_action_family: "list_movements",
|
||||
explicit_intent_candidate: "bank_operations_by_counterparty",
|
||||
explicit_entity_candidates: ["поставщикам"]
|
||||
},
|
||||
followupContext: {
|
||||
previous_discovery_pilot_scope: "business_overview_route_template_v1",
|
||||
previous_discovery_loop_selected_chain_id: "business_overview",
|
||||
previous_filters: {
|
||||
organization: orgName
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.adapter_status).toBe("ready");
|
||||
expect(result.should_run_discovery).toBe(true);
|
||||
expect(result.semantic_data_need).toBe("business overview evidence with bounded analyst interpretation");
|
||||
expect(result.data_need_graph?.business_fact_family).toBe("business_overview");
|
||||
expect(result.turn_meaning_ref).toMatchObject({
|
||||
asked_domain_family: "business_overview",
|
||||
asked_action_family: "vendor_risk_procurement_boundary",
|
||||
explicit_organization_scope: orgName,
|
||||
unsupported_but_understood_family: "vendor_risk_procurement_boundary",
|
||||
stale_replay_forbidden: true
|
||||
});
|
||||
expect(result.turn_meaning_ref?.explicit_entity_candidates).toBeUndefined();
|
||||
expect(result.reason_codes).toContain("mcp_discovery_business_overview_supplier_dependency_followup_boundary");
|
||||
});
|
||||
|
||||
it("keeps supplier dependency follow-ups in the procurement boundary after broad-business meaning normalization", () => {
|
||||
const orgName = "ООО Альтернатива Плюс";
|
||||
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||
userMessage: "а по поставщикам и исходящим платежам от кого зависимость?",
|
||||
assistantTurnMeaning: {
|
||||
asked_domain_family: "business_overview",
|
||||
asked_action_family: "broad_evaluation",
|
||||
explicit_organization_scope: orgName,
|
||||
unsupported_but_understood_family: "broad_business_evaluation"
|
||||
},
|
||||
followupContext: {
|
||||
previous_discovery_pilot_scope: "business_overview_route_template_v1",
|
||||
previous_filters: {
|
||||
organization: orgName
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.adapter_status).toBe("ready");
|
||||
expect(result.should_run_discovery).toBe(true);
|
||||
expect(result.turn_meaning_ref).toMatchObject({
|
||||
asked_domain_family: "business_overview",
|
||||
asked_action_family: "vendor_risk_procurement_boundary",
|
||||
explicit_organization_scope: orgName,
|
||||
unsupported_but_understood_family: "vendor_risk_procurement_boundary",
|
||||
stale_replay_forbidden: true
|
||||
});
|
||||
expect(result.reason_codes).toContain("mcp_discovery_business_overview_supplier_dependency_followup_boundary");
|
||||
});
|
||||
|
||||
it("resumes an open-scope total clarification loop from saved state when the user resolves the pending period with all-time wording", () => {
|
||||
const orgName = "ООО Альтернатива Плюс";
|
||||
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||
|
||||
@@ -303,6 +303,22 @@ describe("assistantTurnMeaningPolicy", () => {
|
||||
expect(supplierQuality.asked_action_family).toBe("broad_evaluation");
|
||||
expect(supplierQuality.unsupported_but_understood_family).toBe("broad_business_evaluation");
|
||||
expect(supplierQuality.reason_codes).toContain("broad_business_evaluation_current_turn_signal");
|
||||
|
||||
const supplierDependencyFollowup = policy.resolveAssistantTurnMeaning({
|
||||
rawUserMessage: "а по поставщикам и исходящим платежам от кого зависимость?"
|
||||
});
|
||||
expect(supplierDependencyFollowup.explicit_intent_candidate).toBeNull();
|
||||
expect(supplierDependencyFollowup.asked_domain_family).toBe("business_summary");
|
||||
expect(supplierDependencyFollowup.asked_action_family).toBe("broad_evaluation");
|
||||
expect(supplierDependencyFollowup.unsupported_but_understood_family).toBe("broad_business_evaluation");
|
||||
|
||||
const nextChecks = policy.resolveAssistantTurnMeaning({
|
||||
rawUserMessage: "что дальше проверять в первую очередь?"
|
||||
});
|
||||
expect(nextChecks.explicit_intent_candidate).toBeNull();
|
||||
expect(nextChecks.asked_domain_family).toBe("business_summary");
|
||||
expect(nextChecks.asked_action_family).toBe("broad_evaluation");
|
||||
expect(nextChecks.unsupported_but_understood_family).toBe("broad_business_evaluation");
|
||||
});
|
||||
|
||||
it("keeps selected-object profitability as an inventory exact intent instead of company overview", () => {
|
||||
|
||||
@@ -149,6 +149,40 @@ describe("counterparty analytics reply builders", () => {
|
||||
expect(reply.text).not.toContain("1. 2020 |");
|
||||
});
|
||||
|
||||
it("preserves raw dependency wording when the address lane receives a canonicalized inflow ranking", () => {
|
||||
const reply = composeFactualReply(
|
||||
"customer_revenue_and_payments",
|
||||
[
|
||||
{
|
||||
period: "2020-03-01T00:00:00Z",
|
||||
registrator: "Поступление 1",
|
||||
account_dt: "",
|
||||
account_kt: "",
|
||||
amount: 500,
|
||||
analytics: ["Малый клиент", "Договор 1"]
|
||||
},
|
||||
{
|
||||
period: "2020-03-02T00:00:00Z",
|
||||
registrator: "Поступление 2",
|
||||
account_dt: "",
|
||||
account_kt: "",
|
||||
amount: 1200,
|
||||
analytics: ["Главный клиент", "Договор 2"]
|
||||
}
|
||||
],
|
||||
{
|
||||
rawUserMessage: "от кого мы больше всего зависим по входящим деньгам?",
|
||||
userMessage: "определить контрагентов с наибольшим объемом входящих денежных потоков"
|
||||
}
|
||||
);
|
||||
|
||||
expect(reply.responseType).toBe("FACTUAL_LIST");
|
||||
expect(reply.text.split("\n")[0]).toContain("Главный сигнал зависимости по входящим деньгам");
|
||||
expect(reply.text.split("\n")[0]).toContain("Главный клиент");
|
||||
expect(reply.text).toContain("сигнал концентрации");
|
||||
expect(reply.text).toContain("не чистая прибыль");
|
||||
});
|
||||
|
||||
it("explains organization activity age as 1C activity rather than legal age", () => {
|
||||
const reply = composeFactualReply(
|
||||
"counterparty_activity_lifecycle",
|
||||
|
||||
Reference in New Issue
Block a user