Архитектура: централизовать party-anchor carryover и referenced-entity follow-up в continuity policy и transition glue

This commit is contained in:
2026-04-19 11:58:56 +03:00
parent 0a423288b9
commit 4f56aa9b2a
7 changed files with 293 additions and 60 deletions
@@ -1,6 +1,8 @@
import { describe, expect, it } from "vitest";
import {
applyHistoricalPartyCarryoverFilters,
applyOrganizationCarryoverFilters,
applyReferencedEntityCarryover,
applyTemporalCarryoverFilters,
buildRootScopedCarryoverFilters,
hydrateInventoryRootFrameState,
@@ -281,4 +283,45 @@ describe("assistantContinuityPolicy organization authority", () => {
organization: "Org Existing"
});
});
it("backfills historical contract and counterparty only for party-driven follow-up families", () => {
const filters = applyHistoricalPartyCarryoverFilters(
{},
true,
"Contract Legacy",
"Counterparty Legacy"
);
expect(filters).toEqual({
contract: "Contract Legacy",
counterparty: "Counterparty Legacy"
});
});
it("applies referenced entity carryover into filters, anchor, and selection mode", () => {
const carryover = applyReferencedEntityCarryover(
{
organization: "Org Alt"
},
null,
null,
"carry_previous_intent",
{
entityType: "counterparty",
value: "SVK Group"
},
false
);
expect(carryover).toEqual({
previousFilters: {
organization: "Org Alt",
counterparty: "SVK Group"
},
previousAnchorType: "counterparty",
previousAnchorValue: "SVK Group",
followupSelectionMode: "carry_referenced_entity",
resolvedCounterpartyFromDisplay: true
});
});
});
@@ -214,6 +214,47 @@ describe("assistantTransitionPolicy", () => {
expect(contract.decision).toBe("continue_previous");
});
it("retargets displayed counterparty follow-up through shared referenced-entity carryover", () => {
const policy = buildPolicy({
findLastAddressAssistantItem: () => ({
text: "1. SVK Group\n2. Gamma",
debug: {
detected_intent: "customer_revenue_and_payments",
extracted_filters: {
organization: 'ООО "Альтернатива Плюс"',
period_from: "2017-01-01",
period_to: "2017-12-31"
}
}
}),
hasAddressFollowupContextSignal: () => true,
inferDisplayedEntityTypeFromIntent: () => "counterparty",
extractDisplayedAddressEntityCandidates: () => [{ entityType: "counterparty", value: "SVK Group" }],
resolveDisplayedAddressEntityMention: () => ({ entityType: "counterparty", value: "SVK Group" }),
resolveAddressIntent: () => ({ intent: "unknown" })
});
const carryover = policy.resolveAddressFollowupCarryoverContext(
"покажи договоры по СВК",
[],
null,
null,
null
);
expect(carryover?.followupSelectionMode).toBe("carry_referenced_entity");
expect(carryover?.followupContext?.target_intent).toBe("list_contracts_by_counterparty");
expect(carryover?.followupContext?.previous_anchor_type).toBe("counterparty");
expect(carryover?.followupContext?.previous_anchor_value).toBe("SVK Group");
expect(carryover?.followupContext?.previous_filters).toMatchObject({
organization: 'ООО "Альтернатива Плюс"',
counterparty: "SVK Group",
period_from: "2017-01-01",
period_to: "2017-12-31"
});
expect(carryover?.followupContext?.resolved_counterparty_from_display).toBe(true);
});
it("retargets same-date inventory follow-up away from receivables intent", () => {
const policy = buildPolicy({
findLastAddressAssistantItem: () => ({