Open-World: направить вопросы о доходности компании в бизнес-обзор

This commit is contained in:
2026-05-05 11:19:28 +03:00
parent 3b97fece2d
commit 0c527e5582
12 changed files with 202 additions and 34 deletions
@@ -2605,11 +2605,12 @@ describe("address intent resolver expansion (M2.3a)", () => {
expect(result.intent).toBe("customer_revenue_and_payments");
});
it("resolves yearly profitability wording into customer revenue intent", () => {
it("defers organization-level yearly profitability wording to business overview discovery", () => {
const result = resolveAddressIntent(
"\u043a\u0430\u043a\u0438\u0435 \u0441\u0430\u043c\u044b\u0435 \u0434\u043e\u0445\u043e\u0434\u043d\u044b\u0435 \u0433\u043e\u0434\u0430 \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u044b"
);
expect(result.intent).toBe("customer_revenue_and_payments");
expect(result.intent).toBe("unknown");
expect(result.reasons).toContain("unicode_business_overview_earnings_deferred_to_discovery");
});
it("resolves major-share revenue wording into customer revenue intent", () => {
@@ -2652,14 +2653,16 @@ describe("address intent resolver expansion (M2.3a)", () => {
expect(result.intent).toBe("contract_usage_and_value");
});
it("resolves revenue-total slang wording into customer revenue intent", () => {
it("defers organization-level revenue-total slang wording to business overview discovery", () => {
const result = resolveAddressIntent("скока денег альтернатива заработала за 22 год");
expect(result.intent).toBe("customer_revenue_and_payments");
expect(result.intent).toBe("unknown");
expect(result.reasons).toContain("unicode_business_overview_earnings_deferred_to_discovery");
});
it("resolves overall-turnover wording into customer revenue intent", () => {
it("defers organization-level overall-turnover wording to business overview discovery", () => {
const result = resolveAddressIntent("какие общие обороты за все время");
expect(result.intent).toBe("customer_revenue_and_payments");
expect(result.intent).toBe("unknown");
expect(result.reasons).toContain("unicode_business_overview_earnings_deferred_to_discovery");
});
it("resolves VAT payment forecast wording into dedicated VAT forecast intent", () => {
@@ -3753,17 +3756,17 @@ describe("address query limited taxonomy and stage diagnostics", { timeout: 1500
expect(["FACTUAL_LIST", "LIMITED_WITH_REASON", "FACTUAL_SUMMARY"]).toContain(result?.response_type);
});
it("routes yearly profitability wording into customer value aggregate recipe", async () => {
it("defers yearly profitability wording out of the exact customer value aggregate recipe", async () => {
const service = new AddressQueryService();
const result = await service.tryHandle(
"\u043a\u0430\u043a\u0438\u0435 \u0441\u0430\u043c\u044b\u0435 \u0434\u043e\u0445\u043e\u0434\u043d\u044b\u0435 \u0433\u043e\u0434\u0430 \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u044b"
);
expect(result?.handled).toBe(true);
expect(result?.debug.detected_intent).toBe("customer_revenue_and_payments");
expect(result?.debug.selected_recipe).toBe("address_customer_revenue_and_payments_v1");
expect(result?.debug.limited_reason_category).not.toBe("unsupported");
expect(result?.debug.mcp_call_status).not.toBe("skipped");
expect(["FACTUAL_LIST", "LIMITED_WITH_REASON", "FACTUAL_SUMMARY"]).toContain(result?.response_type);
expect(result?.debug.detected_intent).toBe("unknown");
expect(result?.debug.selected_recipe).toBeNull();
expect(result?.debug.limited_reason_category).toBe("unsupported");
expect(result?.debug.mcp_call_status).toBe("skipped");
expect(result?.response_type).toBe("LIMITED_WITH_REASON");
});
it("routes typo highest-check wording into customer value aggregate recipe", async () => {
@@ -3819,27 +3822,16 @@ describe("address query limited taxonomy and stage diagnostics", { timeout: 1500
expect(["FACTUAL_LIST", "LIMITED_WITH_REASON", "FACTUAL_SUMMARY"]).toContain(result?.response_type);
});
it("routes revenue-total slang wording into customer value aggregate recipe (no account-missing fallback)", async () => {
it("defers revenue-total slang wording out of exact address recipes", async () => {
const service = new AddressQueryService();
const result = await service.tryHandle("скока денег альтернатива заработала за 22 год");
expect(result?.handled).toBe(true);
expect(result?.debug.detected_intent).toBe("customer_revenue_and_payments");
expect(result?.debug.selected_recipe).toBe("address_customer_revenue_and_payments_v1");
expect(result?.debug.limited_reason_category).not.toBe("missing_anchor");
expect(result?.debug.missing_required_filters).not.toContain("account");
expect(result?.debug.mcp_call_status).not.toBe("skipped");
expect(["FACTUAL_LIST", "LIMITED_WITH_REASON", "FACTUAL_SUMMARY"]).toContain(result?.response_type);
expect(result).toBeNull();
});
it("routes overall-turnover wording into customer value aggregate recipe", async () => {
it("defers overall-turnover wording out of exact address recipes", async () => {
const service = new AddressQueryService();
const result = await service.tryHandle("какие общие обороты за все время");
expect(result?.handled).toBe(true);
expect(result?.debug.detected_intent).toBe("customer_revenue_and_payments");
expect(result?.debug.selected_recipe).toBe("address_customer_revenue_and_payments_v1");
expect(result?.debug.limited_reason_category).not.toBe("unsupported");
expect(result?.debug.mcp_call_status).not.toBe("skipped");
expect(["FACTUAL_LIST", "LIMITED_WITH_REASON", "FACTUAL_SUMMARY"]).toContain(result?.response_type);
expect(result).toBeNull();
});
it("routes VAT payment forecast wording into dedicated VAT forecast recipe", async () => {
@@ -1944,12 +1944,13 @@ describe("assistant MCP discovery turn input adapter", () => {
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.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: "counterparty_value",
asked_action_family: "turnover",
asked_domain_family: "business_overview",
asked_action_family: "broad_evaluation",
explicit_organization_scope: orgName,
unsupported_but_understood_family: "counterparty_value_or_turnover",
unsupported_but_understood_family: "broad_business_evaluation",
stale_replay_forbidden: true
});
expect(result.turn_meaning_ref?.explicit_date_scope).toBeUndefined();
@@ -145,4 +145,27 @@ describe("assistantTurnMeaningPolicy", () => {
expect(meaning.stale_replay_forbidden).toBe(true);
expect(meaning.reason_codes).toContain("broad_business_evaluation_current_turn_signal");
});
it("treats organization-level earnings and best-year wording as business overview", () => {
const policy = buildPolicy({
resolveAddressIntent: () => ({ intent: "customer_revenue_and_payments", confidence: "high" })
});
const earnings = policy.resolveAssistantTurnMeaning({
rawUserMessage: "сколько вообще денег мы заработали за все время?"
});
expect(earnings.explicit_intent_candidate).toBeNull();
expect(earnings.asked_domain_family).toBe("business_summary");
expect(earnings.asked_action_family).toBe("broad_evaluation");
expect(earnings.unsupported_but_understood_family).toBe("broad_business_evaluation");
expect(earnings.stale_replay_forbidden).toBe(true);
const bestYear = policy.resolveAssistantTurnMeaning({
rawUserMessage: "какой у нас самый доходный год"
});
expect(bestYear.explicit_intent_candidate).toBeNull();
expect(bestYear.asked_domain_family).toBe("business_summary");
expect(bestYear.asked_action_family).toBe("broad_evaluation");
expect(bestYear.reason_codes).toContain("broad_business_evaluation_current_turn_signal");
});
});