Архитектура: централизовать 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
@@ -436,6 +436,106 @@ export function applyOrganizationCarryoverFilters(
return nextFilters;
}
export function applyHistoricalPartyCarryoverFilters(
previousFilters: Record<string, unknown> | null,
shouldBackfillHistoricalPartyAnchors: boolean,
historicalContract: unknown,
historicalCounterparty: unknown,
toNonEmptyString: (value: unknown) => string | null = fallbackToNonEmptyString
): Record<string, unknown> {
const nextFilters =
previousFilters && typeof previousFilters === "object" ? { ...previousFilters } : {};
if (!shouldBackfillHistoricalPartyAnchors) {
return nextFilters;
}
if (!toNonEmptyString(nextFilters.contract)) {
nextFilters.contract = toNonEmptyString(historicalContract) ?? undefined;
}
if (!toNonEmptyString(nextFilters.counterparty)) {
nextFilters.counterparty = toNonEmptyString(historicalCounterparty) ?? undefined;
}
return nextFilters;
}
export function applyReferencedEntityCarryover(
previousFilters: Record<string, unknown> | null,
previousAnchorType: string | null,
previousAnchorValue: string | null,
followupSelectionMode: string | null,
resolvedEntityFromFollowup:
| {
entityType?: unknown;
value?: unknown;
}
| null
| undefined,
rootScopedPivot: boolean,
toNonEmptyString: (value: unknown) => string | null = fallbackToNonEmptyString
): {
previousFilters: Record<string, unknown>;
previousAnchorType: string | null;
previousAnchorValue: string | null;
followupSelectionMode: string | null;
resolvedCounterpartyFromDisplay: boolean;
} {
const nextFilters =
previousFilters && typeof previousFilters === "object" ? { ...previousFilters } : {};
if (rootScopedPivot || !resolvedEntityFromFollowup || typeof resolvedEntityFromFollowup !== "object") {
return {
previousFilters: nextFilters,
previousAnchorType,
previousAnchorValue,
followupSelectionMode,
resolvedCounterpartyFromDisplay: false
};
}
const entityType = toNonEmptyString(resolvedEntityFromFollowup.entityType);
const entityValue = toNonEmptyString(resolvedEntityFromFollowup.value);
if (!entityType || !entityValue) {
return {
previousFilters: nextFilters,
previousAnchorType,
previousAnchorValue,
followupSelectionMode,
resolvedCounterpartyFromDisplay: false
};
}
let resolvedCounterpartyFromDisplay = false;
if (entityType === "counterparty") {
nextFilters.counterparty = entityValue;
previousAnchorType = "counterparty";
previousAnchorValue = entityValue;
resolvedCounterpartyFromDisplay = true;
} else if (entityType === "contract") {
nextFilters.contract = entityValue;
previousAnchorType = "contract";
previousAnchorValue = entityValue;
} else if (entityType === "item") {
nextFilters.item = entityValue;
previousAnchorType = "item";
previousAnchorValue = entityValue;
} else {
return {
previousFilters: nextFilters,
previousAnchorType,
previousAnchorValue,
followupSelectionMode,
resolvedCounterpartyFromDisplay: false
};
}
return {
previousFilters: nextFilters,
previousAnchorType,
previousAnchorValue,
followupSelectionMode:
followupSelectionMode !== "switch_to_suggested_intent" ? "carry_referenced_entity" : followupSelectionMode,
resolvedCounterpartyFromDisplay
};
}
export function buildInventoryRootFrameFromAddressDebug(
debug: Record<string, unknown> | null,
toNonEmptyString: (value: unknown) => string | null = fallbackToNonEmptyString
@@ -1,6 +1,8 @@
// @ts-nocheck
import {
applyHistoricalPartyCarryoverFilters,
applyOrganizationCarryoverFilters,
applyReferencedEntityCarryover,
applyTemporalCarryoverFilters,
buildRootScopedCarryoverFilters,
buildInventoryRootFrameFromAddressDebug,
@@ -759,18 +761,13 @@ export function createAssistantTransitionPolicy(deps) {
sourceIntentHint === "list_documents_by_contract" ||
sourceIntentHint === "bank_operations_by_contract" ||
sourceIntentHint === "open_items_by_counterparty_or_contract";
if (shouldBackfillHistoricalPartyAnchors && !deps.toNonEmptyString(previousFilters.contract)) {
const historicalContract = deps.findRecentAddressFilterValue(items, "contract");
if (historicalContract) {
previousFilters.contract = historicalContract;
}
}
if (shouldBackfillHistoricalPartyAnchors && !deps.toNonEmptyString(previousFilters.counterparty)) {
const historicalCounterparty = deps.findRecentAddressFilterValue(items, "counterparty");
if (historicalCounterparty) {
previousFilters.counterparty = historicalCounterparty;
}
}
previousFilters = applyHistoricalPartyCarryoverFilters(
previousFilters,
shouldBackfillHistoricalPartyAnchors,
deps.findRecentAddressFilterValue(items, "contract"),
deps.findRecentAddressFilterValue(items, "counterparty"),
deps.toNonEmptyString
);
const historicalOrganization = deps.findRecentAddressFilterValue(items, "organization");
const authorityActiveOrganization =
deps.normalizeOrganizationScopeValue(organizationAuthority.activeOrganization) ??
@@ -861,24 +858,22 @@ export function createAssistantTransitionPolicy(deps) {
userMessage,
resolvedEntityFromFollowup.entityType
);
if (resolvedEntityFromFollowup.entityType === "counterparty") {
previousFilters.counterparty = resolvedEntityFromFollowup.value;
previousAnchorType = "counterparty";
previousAnchor = resolvedEntityFromFollowup.value;
resolvedCounterpartyFromDisplay = true;
} else if (resolvedEntityFromFollowup.entityType === "contract") {
previousFilters.contract = resolvedEntityFromFollowup.value;
previousAnchorType = "contract";
previousAnchor = resolvedEntityFromFollowup.value;
} else if (resolvedEntityFromFollowup.entityType === "item") {
previousFilters.item = resolvedEntityFromFollowup.value;
previousAnchorType = "item";
previousAnchor = resolvedEntityFromFollowup.value;
}
if (followupSelectionMode !== "switch_to_suggested_intent") {
followupSelectionMode = "carry_referenced_entity";
}
}
({
previousFilters,
previousAnchorType,
previousAnchorValue: previousAnchor,
followupSelectionMode,
resolvedCounterpartyFromDisplay
} = applyReferencedEntityCarryover(
previousFilters,
previousAnchorType,
previousAnchor,
followupSelectionMode,
resolvedEntityFromFollowup,
rootScopedPivot,
deps.toNonEmptyString
));
if (
!rootScopedPivot &&
!deps.toNonEmptyString(previousFilters.item) &&