Исправить компактные follow-up ответы по денежному итогу 1С
This commit is contained in:
@@ -224,6 +224,89 @@ describe("assistant address orchestration runtime adapter", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("rebuilds business overview period carryover for compact cashflow follow-up when address carryover is absent", async () => {
|
||||
const runMcpDiscoveryRuntimeEntryPoint = vi.fn(async () => ({
|
||||
schema_version: "assistant_mcp_discovery_runtime_entry_point_v1",
|
||||
policy_owner: "assistantMcpDiscoveryRuntimeEntryPoint",
|
||||
entry_status: "bridge_executed",
|
||||
hot_runtime_wired: false,
|
||||
discovery_attempted: true
|
||||
}));
|
||||
const input = buildInput({
|
||||
userMessage:
|
||||
"\u0434\u0430\u0439 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u043e\u0439 \u0434\u0435\u043d\u044c\u0433\u0438 \u0431\u0435\u0437 \u0440\u0430\u0437\u0431\u0438\u0432\u043a\u0438",
|
||||
sessionItems: [
|
||||
{
|
||||
role: "assistant",
|
||||
debug: {
|
||||
assistant_mcp_discovery_entry_point_v1: {
|
||||
turn_input: {
|
||||
data_need_graph: {
|
||||
business_fact_family: "business_overview",
|
||||
ranking_need: "top_desc"
|
||||
},
|
||||
turn_meaning_ref: {
|
||||
explicit_date_scope: "2020",
|
||||
explicit_organization_scope:
|
||||
"\u041e\u041e\u041e \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u041f\u043b\u044e\u0441"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
runAddressLlmPreDecompose: vi.fn(async () => ({
|
||||
attempted: true,
|
||||
applied: false,
|
||||
effectiveMessage:
|
||||
"\u0434\u0430\u0439 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u043e\u0439 \u0434\u0435\u043d\u044c\u0433\u0438 \u0431\u0435\u0437 \u0440\u0430\u0437\u0431\u0438\u0432\u043a\u0438",
|
||||
reason: "raw_kept",
|
||||
predecomposeContract: {
|
||||
mode: "unsupported",
|
||||
intent: "unknown",
|
||||
period: {}
|
||||
}
|
||||
})),
|
||||
resolveAddressFollowupCarryoverContext: vi.fn(() => null),
|
||||
resolveAssistantOrchestrationDecision: vi.fn(() => ({
|
||||
runAddressLane: false,
|
||||
livingMode: "chat",
|
||||
livingReason: "unsupported_current_turn_meaning_boundary",
|
||||
toolGateDecision: "skip_address_lane",
|
||||
toolGateReason: "unsupported_current_turn_meaning_boundary",
|
||||
orchestrationContract: {
|
||||
schema_version: "assistant_orchestration_contract_v1",
|
||||
assistant_turn_meaning: {
|
||||
schema_version: "assistant_turn_meaning_v1",
|
||||
asked_domain_family: "business_summary",
|
||||
asked_action_family: "broad_evaluation",
|
||||
unsupported_but_understood_family: "broad_business_evaluation"
|
||||
}
|
||||
}
|
||||
})),
|
||||
runMcpDiscoveryRuntimeEntryPoint
|
||||
});
|
||||
|
||||
await buildAssistantAddressOrchestrationRuntime(input);
|
||||
|
||||
expect(runMcpDiscoveryRuntimeEntryPoint).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
followupContext: expect.objectContaining({
|
||||
previous_discovery_pilot_scope: "business_overview_route_template_v1",
|
||||
previous_seeded_ranking_need: "top_desc",
|
||||
previous_filters: expect.objectContaining({
|
||||
period_from: "2020-01-01",
|
||||
period_to: "2020-12-31"
|
||||
}),
|
||||
root_filters: expect.objectContaining({
|
||||
period_from: "2020-01-01",
|
||||
period_to: "2020-12-31"
|
||||
})
|
||||
})
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it("passes grounded discovery follow-up carryover into MCP discovery entry point for a short year switch", async () => {
|
||||
const runMcpDiscoveryRuntimeEntryPoint = vi.fn(async () => ({
|
||||
schema_version: "assistant_mcp_discovery_runtime_entry_point_v1",
|
||||
|
||||
@@ -704,6 +704,80 @@ describe("assistant MCP discovery response candidate", () => {
|
||||
expect(candidate.reply_text).not.toContain("wide overview");
|
||||
});
|
||||
|
||||
it("uses compact cashflow output for one-line no-breakdown wording", () => {
|
||||
const candidate = buildAssistantMcpDiscoveryResponseCandidate(
|
||||
entryPoint({
|
||||
turn_input: {
|
||||
adapter_status: "ready",
|
||||
turn_meaning_ref: {
|
||||
raw_message:
|
||||
"\u0434\u0430\u0439 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u043e\u0439 \u0434\u0435\u043d\u044c\u0433\u0438 \u0431\u0435\u0437 \u0440\u0430\u0437\u0431\u0438\u0432\u043a\u0438",
|
||||
asked_action_family: "broad_evaluation",
|
||||
unsupported_but_understood_family: "broad_business_evaluation",
|
||||
explicit_date_scope: "2020"
|
||||
},
|
||||
data_need_graph: {
|
||||
business_fact_family: "business_overview",
|
||||
ranking_need: null,
|
||||
reason_codes: [
|
||||
"data_need_graph_family_business_overview",
|
||||
"data_need_graph_business_overview_direct_money_answer"
|
||||
]
|
||||
}
|
||||
},
|
||||
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: {
|
||||
period_scope: "2020",
|
||||
incoming_customer_revenue: {
|
||||
total_amount_human_ru: "47 628 853,03 \u0440\u0443\u0431."
|
||||
},
|
||||
outgoing_supplier_payout: {
|
||||
total_amount_human_ru: "43 763 351,53 \u0440\u0443\u0431."
|
||||
},
|
||||
net_amount_human_ru: "3 865 501,50 \u0440\u0443\u0431.",
|
||||
net_direction: "net_incoming",
|
||||
top_customers: [
|
||||
{
|
||||
axis_value: "\u0421\u0411\u0415\u0420\u0411\u0410\u041d\u041a, \u041f\u0410\u041e",
|
||||
total_amount_human_ru: "12 792 194,31 \u0440\u0443\u0431."
|
||||
}
|
||||
],
|
||||
top_suppliers: [
|
||||
{
|
||||
axis_value: "\u0414\u0435\u043f\u0430\u0440\u0442\u0430\u043c\u0435\u043d\u0442",
|
||||
total_amount_human_ru: "9 612 904,90 \u0440\u0443\u0431."
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
answer_draft: {
|
||||
answer_mode: "confirmed_with_bounded_inference",
|
||||
headline: "wide overview should not leak",
|
||||
confirmed_lines: [],
|
||||
inference_lines: [],
|
||||
unknown_lines: [],
|
||||
limitation_lines: [],
|
||||
next_step_line: "\u0427\u0442\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0434\u0430\u043b\u044c\u0448\u0435"
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
expect(candidate.reply_text).toContain("\u0437\u0430 2020");
|
||||
expect(candidate.reply_text).toContain("47 628 853,03");
|
||||
expect(candidate.reply_text).toContain("43 763 351,53");
|
||||
expect(candidate.reply_text).toContain("3 865 501,50");
|
||||
expect(candidate.reply_text).not.toContain("\u0421\u0411\u0415\u0420\u0411\u0410\u041d\u041a");
|
||||
expect(candidate.reply_text).not.toContain("\u0427\u0442\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c");
|
||||
expect(candidate.reply_text).not.toContain("wide overview");
|
||||
});
|
||||
|
||||
it("labels organization-scoped bidirectional value-flow continuations as company scope", () => {
|
||||
const candidate = buildAssistantMcpDiscoveryResponseCandidate(
|
||||
entryPoint({
|
||||
|
||||
@@ -2380,6 +2380,47 @@ describe("assistant MCP discovery turn input adapter", () => {
|
||||
expect(result.data_need_graph?.reason_codes).toContain("data_need_graph_business_overview_direct_money_answer");
|
||||
});
|
||||
|
||||
it("preserves previous overview period for compact cashflow display follow-ups", () => {
|
||||
const orgName = "\u041e\u041e\u041e \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u041f\u043b\u044e\u0441";
|
||||
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||
userMessage:
|
||||
"\u0434\u0430\u0439 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u043e\u0439 \u0434\u0435\u043d\u044c\u0433\u0438 \u0431\u0435\u0437 \u0440\u0430\u0437\u0431\u0438\u0432\u043a\u0438",
|
||||
assistantTurnMeaning: {
|
||||
asked_domain_family: "business_summary",
|
||||
asked_action_family: "broad_evaluation",
|
||||
unsupported_but_understood_family: "broad_business_evaluation",
|
||||
stale_replay_forbidden: true,
|
||||
reason_codes: ["compact_cashflow_display_current_turn_signal"]
|
||||
},
|
||||
followupContext: {
|
||||
previous_discovery_pilot_scope: "business_overview_route_template_v1",
|
||||
previous_filters: {
|
||||
organization: orgName,
|
||||
period_from: "2020-01-01",
|
||||
period_to: "2020-12-31"
|
||||
},
|
||||
previous_seeded_ranking_need: "top_desc"
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.adapter_status).toBe("ready");
|
||||
expect(result.should_run_discovery).toBe(true);
|
||||
expect(result.data_need_graph?.business_fact_family).toBe("business_overview");
|
||||
expect(result.data_need_graph?.ranking_need).toBeNull();
|
||||
expect(result.turn_meaning_ref).toMatchObject({
|
||||
asked_domain_family: "business_overview",
|
||||
asked_action_family: "broad_evaluation",
|
||||
explicit_organization_scope: orgName,
|
||||
explicit_date_scope: "2020",
|
||||
unsupported_but_understood_family: "broad_business_evaluation",
|
||||
stale_replay_forbidden: true
|
||||
});
|
||||
expect(result.reason_codes).toContain("mcp_discovery_date_scope_from_followup_context");
|
||||
expect(result.reason_codes).not.toContain("mcp_discovery_topic_switch_suppressed_followup_scope");
|
||||
expect(result.data_need_graph?.reason_codes).toContain("data_need_graph_business_overview_direct_money_answer");
|
||||
expect(result.data_need_graph?.reason_codes).not.toContain("data_need_graph_all_time_scope_hint");
|
||||
});
|
||||
|
||||
it("routes organization-level profit and margin wording to business overview instead of exact value recipes", () => {
|
||||
const orgName = "\u041e\u041e\u041e \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u041f\u043b\u044e\u0441";
|
||||
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||
|
||||
@@ -216,6 +216,32 @@ describe("assistantTurnMeaningPolicy", () => {
|
||||
expect(meaning.reason_codes).not.toContain("counterparty_turnover_current_turn_signal");
|
||||
});
|
||||
|
||||
it.each([
|
||||
"\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438 \u0434\u0435\u043d\u044c\u0433\u0430\u043c\u0438 \u0431\u0435\u0437 \u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\u043e\u0432?",
|
||||
"\u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0442\u043e\u0433: \u043f\u0440\u0438\u0448\u043b\u043e, \u0443\u0448\u043b\u043e, \u043d\u0435\u0442\u0442\u043e",
|
||||
"\u0434\u0430\u0439 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u043e\u0439 \u0434\u0435\u043d\u044c\u0433\u0438 \u0431\u0435\u0437 \u0440\u0430\u0437\u0431\u0438\u0432\u043a\u0438",
|
||||
"\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u0438 \u0437\u0430\u043f\u043b\u0430\u0442\u0438\u043b\u0438 \u0431\u0435\u0437 \u0434\u0435\u0442\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438"
|
||||
])("treats compact cashflow wording '%s' as business-summary display request", (rawUserMessage) => {
|
||||
const policy = buildPolicy({
|
||||
resolveAddressIntent: () => ({ intent: "customer_revenue_and_payments", confidence: "high" })
|
||||
});
|
||||
|
||||
const meaning = policy.resolveAssistantTurnMeaning({
|
||||
rawUserMessage,
|
||||
effectiveAddressUserMessage:
|
||||
"\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043e\u0431\u043e\u0440\u043e\u0442 \u0438 \u0432\u044b\u0440\u0443\u0447\u043a\u0443 \u043f\u043e \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 \u0431\u0435\u0437 \u0440\u0430\u0437\u0440\u0435\u0437\u0430 \u043f\u043e \u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\u0430\u043c."
|
||||
});
|
||||
|
||||
expect(meaning.explicit_intent_candidate).toBeNull();
|
||||
expect(meaning.asked_domain_family).toBe("business_summary");
|
||||
expect(meaning.asked_action_family).toBe("broad_evaluation");
|
||||
expect(meaning.explicit_entity_candidates).toEqual([]);
|
||||
expect(meaning.unsupported_but_understood_family).toBe("broad_business_evaluation");
|
||||
expect(meaning.stale_replay_forbidden).toBe(true);
|
||||
expect(meaning.reason_codes).toContain("compact_cashflow_display_current_turn_signal");
|
||||
expect(meaning.reason_codes).not.toContain("counterparty_turnover_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" })
|
||||
|
||||
Reference in New Issue
Block a user