ГЛОБАЛЬНЫЙ РЕФАКТОРИНГ АРХИТЕКТУРЫ - Этап 4.8: референциальная continuity для follow-up по контрагентам и pivot операции

This commit is contained in:
2026-04-12 10:36:44 +03:00
parent a49212608f
commit ca2feab893
7 changed files with 584 additions and 17 deletions
@@ -258,6 +258,18 @@ function hasAddressFollowupContextSignal(text) {
}
return tokenCount <= 6;
}
function isValueCounterpartyIntent(intent) {
return (intent === "customer_revenue_and_payments" ||
intent === "supplier_payouts_profile" ||
intent === "contract_usage_and_value");
}
function hasBroadCounterpartyRankingCue(text) {
const normalized = String(text ?? "").toLowerCase();
if (!normalized) {
return false;
}
return /(?:\bкто\b|\bкакие\b|\bкакой\b|\bтоп\b|\bсписок\b|\bвсе\b|\bвсех\b|\bвсего\b|\bclients?\b|\bcounterpart(?:y|ies)\b|контрагент|клиент|заказчик)/iu.test(normalized);
}
function mergeFollowupFilters(current, intent, userMessage, followupContext) {
const merged = { ...current };
const reasons = [];
@@ -294,6 +306,24 @@ function mergeFollowupFilters(current, intent, userMessage, followupContext) {
reasons.push(currentCounterparty ? "counterparty_replaced_from_followup_context" : "counterparty_from_followup_context");
}
}
if (isValueCounterpartyIntent(intent)) {
const inheritedCounterparty = previousCounterparty ??
(followupContext.previous_anchor_type === "counterparty" ? previousAnchorValue : null);
const currentCounterparty = toNonEmptyString(merged.counterparty);
const previousIntentIsValueCounterparty = isValueCounterpartyIntent(followupContext.previous_intent ?? "unknown");
const resolvedCounterpartyFromDisplay = followupContext.resolved_counterparty_from_display === true;
const allowCarryover = !hasBroadCounterpartyRankingCue(userMessage) &&
(resolvedCounterpartyFromDisplay || previousIntentIsValueCounterparty);
const shouldInheritCounterparty = allowCarryover &&
(!currentCounterparty ||
(Boolean(inheritedCounterparty) &&
isLowQualityCounterpartyAnchor(currentCounterparty) &&
!isLowQualityCounterpartyAnchor(inheritedCounterparty)));
if (inheritedCounterparty && shouldInheritCounterparty) {
merged.counterparty = inheritedCounterparty;
reasons.push(currentCounterparty ? "counterparty_replaced_from_followup_context" : "counterparty_from_followup_context");
}
}
if (intent === "list_documents_by_contract" || intent === "bank_operations_by_contract") {
const inheritedContract = previousContract ?? (followupContext.previous_anchor_type === "contract" ? previousAnchorValue : null);
const currentContract = toNonEmptyString(merged.contract);