Архитектура: закрыть phase17 clarification-resume и обновить readiness-статус перед расширением доменов

This commit is contained in:
2026-04-19 17:17:09 +03:00
parent af15e21bf6
commit 0e098cde38
18 changed files with 842 additions and 87 deletions
@@ -15,6 +15,7 @@ const addressQueryShapeClassifier_1 = require("../addressQueryShapeClassifier");
const addressIntentResolver_1 = require("../addressIntentResolver");
const addressFilterExtractor_1 = require("../addressFilterExtractor");
const inventoryLifecycleCueHelpers_1 = require("../inventoryLifecycleCueHelpers");
const assistantOrganizationMatcher_1 = require("../assistantOrganizationMatcher");
const semanticHintOverlay_1 = require("./semanticHintOverlay");
function hasExplicitPeriodWindow(filters) {
return ((typeof filters.period_from === "string" && filters.period_from.trim().length > 0) ||
@@ -287,6 +288,23 @@ function isInventoryLifecycleHistoryIntent(intent) {
intent === "inventory_sale_trace_for_item" ||
intent === "inventory_purchase_to_sale_chain");
}
function shouldSuppressInventoryCounterpartyAlias(intent, counterparty, organization) {
if (intent !== "inventory_on_hand_as_of_date") {
return false;
}
if (!counterparty || !organization) {
return false;
}
if ((0, assistantOrganizationMatcher_1.organizationsLikelySameEntity)(counterparty, organization)) {
return true;
}
const counterpartyNorm = (0, assistantOrganizationMatcher_1.normalizeOrganizationScopeSearchText)(counterparty);
const organizationNorm = (0, assistantOrganizationMatcher_1.normalizeOrganizationScopeSearchText)(organization);
if (!counterpartyNorm || !organizationNorm) {
return false;
}
return organizationNorm.includes(counterpartyNorm) || counterpartyNorm.includes(organizationNorm);
}
function buildInventoryRootFollowupContext(followupContext) {
if (!followupContext || !followupContext.root_intent || !followupContext.root_filters) {
return followupContext;
@@ -633,21 +651,48 @@ function mergeFollowupFilters(current, intent, userMessage, followupContext) {
const allTimeRequested = hasAllTimeHint(userMessage);
const sameDateRequested = hasSameDateHint(userMessage) || hasSameDatePrepositionHint(userMessage);
const samePeriodRequested = hasSamePeriodHint(userMessage);
const hasFollowupSignal = hasAddressFollowupContextSignal(userMessage);
const hasExplicitPeriodInMessage = hasExplicitPeriodLiteral(userMessage);
const hasExplicitCurrentDateInMessage = hasExplicitCurrentDateHint(userMessage);
const explicitQuotedItem = extractSelectedObjectItemFromFollowupText(userMessage);
if (!toNonEmptyString(merged.organization) && previousOrganization) {
merged.organization = previousOrganization;
reasons.push("organization_from_followup_context");
}
if (intent === "inventory_on_hand_as_of_date" &&
followupContext.previous_intent === "inventory_on_hand_as_of_date" &&
followupContext.target_intent === "inventory_on_hand_as_of_date" &&
followupContext.previous_anchor_type === "organization" &&
!hasFollowupSignal &&
!hasExplicitPeriodInMessage &&
!hasExplicitCurrentDateInMessage &&
toNonEmptyString(merged.counterparty)) {
delete merged.counterparty;
reasons.push("counterparty_cleared_from_organization_clarification_selection");
}
if (intent === "list_documents_by_counterparty" ||
intent === "bank_operations_by_counterparty" ||
intent === "list_contracts_by_counterparty") {
const inheritedCounterparty = previousCounterparty ??
(followupContext.previous_anchor_type === "counterparty" ? previousAnchorValue : null);
const currentCounterparty = toNonEmptyString(merged.counterparty);
const shouldInheritCounterparty = !currentCounterparty ||
(Boolean(inheritedCounterparty) &&
isLowQualityCounterpartyAnchor(currentCounterparty) &&
!isLowQualityCounterpartyAnchor(inheritedCounterparty));
const organizationReference = toNonEmptyString(merged.organization) ??
previousOrganization ??
(followupContext.previous_anchor_type === "organization" ? previousAnchorValue : null);
const currentCounterpartyLooksLikeOrganization = shouldSuppressInventoryCounterpartyAlias(intent, currentCounterparty, organizationReference);
const inheritedCounterpartyLooksLikeOrganization = shouldSuppressInventoryCounterpartyAlias(intent, inheritedCounterparty, organizationReference);
if (!currentCounterparty && inheritedCounterpartyLooksLikeOrganization) {
reasons.push("counterparty_cleared_as_organization_scope_alias");
}
if (currentCounterpartyLooksLikeOrganization) {
delete merged.counterparty;
reasons.push("counterparty_cleared_as_organization_scope_alias");
}
const shouldInheritCounterparty = !inheritedCounterpartyLooksLikeOrganization &&
(!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");
@@ -723,7 +768,7 @@ function mergeFollowupFilters(current, intent, userMessage, followupContext) {
intent === "vat_payable_confirmed_as_of_date" ||
intent === "vat_payable_forecast" ||
intent === "vat_liability_confirmed_for_tax_period") {
const hasFollowupSignalForConfirmed = hasAddressFollowupContextSignal(userMessage);
const hasFollowupSignalForConfirmed = hasFollowupSignal;
const inheritedContract = previousContract ?? (followupContext.previous_anchor_type === "contract" ? previousAnchorValue : null);
const currentContract = toNonEmptyString(merged.contract);
const shouldInheritContract = !currentContract ||
@@ -948,9 +993,6 @@ function mergeFollowupFilters(current, intent, userMessage, followupContext) {
reasons.push("period_to_cleared_for_lifecycle_followup");
}
}
const hasFollowupSignal = hasAddressFollowupContextSignal(userMessage);
const hasExplicitPeriodInMessage = hasExplicitPeriodLiteral(userMessage);
const hasExplicitCurrentDateInMessage = hasExplicitCurrentDateHint(userMessage);
const inventoryLifecycleHistoryIntent = isInventoryLifecycleHistoryIntent(intent);
const asOfPrimaryIntent = intent === "account_balance_snapshot" ||
intent === "documents_forming_balance" ||
@@ -967,6 +1009,18 @@ function mergeFollowupFilters(current, intent, userMessage, followupContext) {
intent === "vat_payable_confirmed_as_of_date";
const currentHasPeriod = hasExplicitPeriodWindow(merged);
const previousHasPeriod = hasExplicitPeriodWindow(previous);
const currentCounterpartyExplicit = toNonEmptyString(merged.counterparty);
const currentContractExplicit = toNonEmptyString(merged.contract);
const currentItemExplicit = toNonEmptyString(merged.item);
const currentAccountExplicit = toNonEmptyString(merged.account);
const shouldSuppressGenericPeriodCarryover = (Boolean(currentCounterpartyExplicit) &&
!isLowQualityCounterpartyAnchor(currentCounterpartyExplicit) &&
currentCounterpartyExplicit !== previousCounterparty) ||
(Boolean(currentContractExplicit) &&
!isLowQualityContractAnchor(currentContractExplicit) &&
currentContractExplicit !== previousContract) ||
(Boolean(currentItemExplicit) && currentItemExplicit !== previousItem) ||
(Boolean(currentAccountExplicit) && currentAccountExplicit !== previousAccount);
const vatRelativeMonthFollowup = relativeMonthFromFollowupYear &&
(intent === "vat_payable_confirmed_as_of_date" ||
intent === "vat_payable_forecast" ||
@@ -1006,7 +1060,8 @@ function mergeFollowupFilters(current, intent, userMessage, followupContext) {
hasFollowupSignal &&
!hasExplicitPeriodInMessage &&
!inventoryLifecycleHistoryIntent &&
!vatRelativeMonthFollowup) {
!vatRelativeMonthFollowup &&
!shouldSuppressGenericPeriodCarryover) {
if (previousPeriodFrom) {
merged.period_from = previousPeriodFrom;
}
@@ -1038,6 +1093,16 @@ function mergeFollowupFilters(current, intent, userMessage, followupContext) {
: "as_of_date_derived_from_period_for_open_contracts");
}
}
const finalOrganizationReference = toNonEmptyString(merged.organization) ??
previousOrganization ??
(followupContext.previous_anchor_type === "organization" ? previousAnchorValue : null);
const finalCounterparty = toNonEmptyString(merged.counterparty);
if (shouldSuppressInventoryCounterpartyAlias(intent, finalCounterparty, finalOrganizationReference)) {
delete merged.counterparty;
if (!reasons.includes("counterparty_cleared_as_organization_scope_alias")) {
reasons.push("counterparty_cleared_as_organization_scope_alias");
}
}
return { filters: merged, reasons };
}
function resolveMissingRequiredFilters(intent, filters) {