NODEDC_1C/llm_normalizer/backend/dist/services/assistantTransitionPolicy.js

629 lines
38 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use strict";
// @ts-nocheck
Object.defineProperty(exports, "__esModule", { value: true });
exports.createAssistantTransitionPolicy = createAssistantTransitionPolicy;
function createAssistantTransitionPolicy(deps) {
function hasInventoryRootRestatementLikeSignal(userMessage, sourceIntentHint, hasInventoryRootFrame) {
if (!hasInventoryRootFrame) {
return false;
}
const normalized = deps
.compactWhitespace(deps.repairAddressMojibake(String(userMessage ?? "")).toLowerCase())
.replace(/ё/g, "е");
if (!normalized) {
return false;
}
if (deps.countTokens(normalized) > 10) {
return false;
}
const hasInventoryLexeme = /(?:остат|склад|товар|номенклатур|позиц)/iu.test(normalized);
const hasRestatementCue = /(?:еще\s+раз|снова|повтори|повтори\s+еще\s+раз|верни|покажи)/iu.test(normalized) &&
/(?:на\s+ту\s+же\s+дат[ауеы]|на\s+эту\s+же\s+дат[ауеы]|на\s+эту\s+дат[ауеы]|эту\s+дат[ауеы]|та\s+же\s+дата|тот\s+же\s+период|этот\s+же\s+период)/iu.test(normalized);
const hasBareSnapshotSameDateCue = hasInventoryLexeme &&
/(?:РЅР°\s+ту\s+Р¶Рµ\s+дат[ауеы]|РЅР°\s+эту\s+Р¶Рµ\s+дат[ауеы]|РЅР°\s+эту\s+дат[ауеы]|эту\s+дат[ауеы]|та\s+Р¶Рµ\s+дата|СРѕС\s+Р¶Рµ\s+период|этот\s+Р¶Рµ\s+период)/iu.test(normalized);
const bareSnapshotSameDatePhrases = [
"\u043d\u0430 \u0442\u0443 \u0436\u0435 \u0434\u0430\u0442",
"\u043d\u0430 \u044d\u0442\u0443 \u0436\u0435 \u0434\u0430\u0442",
"\u043d\u0430 \u044d\u0442\u0443 \u0434\u0430\u0442",
"\u044d\u0442\u0443 \u0434\u0430\u0442",
"\u0442\u0430 \u0436\u0435 \u0434\u0430\u0442\u0430",
"\u0442\u043e\u0442 \u0436\u0435 \u043f\u0435\u0440\u0438\u043e\u0434",
"\u044d\u0442\u043e\u0442 \u0436\u0435 \u043f\u0435\u0440\u0438\u043e\u0434"
];
const hasBareSnapshotSameDatePhraseCue = hasInventoryLexeme && bareSnapshotSameDatePhrases.some((phrase) => normalized.includes(phrase));
return (hasInventoryLexeme &&
(hasRestatementCue || hasBareSnapshotSameDateCue || hasBareSnapshotSameDatePhraseCue) &&
!deps.hasForeignAccountingPivotOverInventoryMessage(normalized));
}
function shouldKeepPreviousIntentForShortCounterpartyRetarget(userMessage, sourceIntent) {
const normalized = deps.compactWhitespace(deps.repairAddressMojibake(String(userMessage ?? "")).toLowerCase());
if (!normalized || deps.countTokens(normalized) > 4) {
return false;
}
if (sourceIntent !== "list_documents_by_counterparty" && sourceIntent !== "list_documents_by_contract") {
return false;
}
if (/(?:банк|выписк|плат[её]ж|оплат|списан|поступлен|bank|payment|wire|statement)/iu.test(normalized)) {
return false;
}
return /^(?:Р°|Рё|РЅСѓ)?\s*РїРѕ\s+[a-zР°-СЏС0-9._-]{2,}(?:\s+[a-zР°-СЏС0-9._-]{2,})?$/iu.test(normalized);
}
function shouldKeepPreviousIntentForShortCounterpartyRetargetV2(userMessage, sourceIntent) {
const normalized = deps.compactWhitespace(deps.repairAddressMojibake(String(userMessage ?? "")).toLowerCase());
if (!normalized || deps.countTokens(normalized) > 4) {
return false;
}
if (sourceIntent !== "list_documents_by_counterparty" && sourceIntent !== "list_documents_by_contract") {
return false;
}
if (/(?:bank|payment|wire|statement)/iu.test(normalized)) {
return false;
}
return /^(?:а|и|ну)?\s*(?:покажи\s+)?по\s+[a-zа-яё0-9._-]{2,}(?:\s+[a-zа-яё0-9._-]{2,})?$/iu.test(normalized);
}
function inferStandaloneAddressTopicFamily(userMessage) {
const normalized = deps.compactWhitespace(deps.repairAddressMojibake(String(userMessage ?? "")).toLowerCase());
if (!normalized) {
return null;
}
if (/(?:ндс|vat)/iu.test(normalized)) {
return "vat";
}
if (/(?:остат|склад|товар|номенклатур|позици)/iu.test(normalized)) {
return "inventory";
}
return null;
}
function resolveDisplayedEntityRetargetIntent(userMessage, entityType) {
const normalized = deps.compactWhitespace(deps.repairAddressMojibake(String(userMessage ?? "")).toLowerCase());
if (!normalized) {
return null;
}
if (entityType === "counterparty") {
if (/(?:договор|контракт)/iu.test(normalized)) {
return "list_contracts_by_counterparty";
}
if (/(?:банк|выписк|плат[её]ж|оплат|statement|payment|wire)/iu.test(normalized)) {
return "bank_operations_by_counterparty";
}
if (/(?:документ|накладн|счет|сч[её]т|акт|реализац|поступл)/iu.test(normalized)) {
return "list_documents_by_counterparty";
}
if (/(?:сколько\s+денег|сколько\s+принес|выручк|сумм[аы]?|оплатил|продаж)/iu.test(normalized)) {
return "customer_revenue_and_payments";
}
return null;
}
if (entityType === "contract") {
if (/(?:банк|выписк|плат[её]ж|оплат|statement|payment|wire)/iu.test(normalized)) {
return "bank_operations_by_contract";
}
if (/(?:документ|накладн|счет|сч[её]т|акт|реализац|поступл)/iu.test(normalized)) {
return "list_documents_by_contract";
}
}
return null;
}
function resolveAddressFollowupCarryoverContext(userMessage, items, alternateMessage = null, llmPreDecomposeMeta = null, addressNavigationState = null) {
const previousAddressItem = deps.findLastAddressAssistantItem(items);
const previousAddressDebug = previousAddressItem?.debug ?? null;
const lastOrganizationClarificationDebug = deps.findLastOrganizationClarificationAddressDebug(items);
const organizationClarificationCandidates = Array.isArray(lastOrganizationClarificationDebug?.organization_candidates)
? deps.mergeKnownOrganizations(lastOrganizationClarificationDebug.organization_candidates)
: [];
const organizationClarificationSelection = deps.resolveOrganizationSelectionFromMessage(userMessage, organizationClarificationCandidates) ??
(deps.toNonEmptyString(alternateMessage)
? deps.resolveOrganizationSelectionFromMessage(String(alternateMessage ?? ""), organizationClarificationCandidates)
: null);
const hasOrganizationClarificationContinuation = Boolean(lastOrganizationClarificationDebug && organizationClarificationSelection);
const followupOffer = previousAddressDebug ? deps.buildAddressFollowupOffer(previousAddressDebug) : null;
const hasImplicitContinuationSignal = Boolean(previousAddressDebug) &&
Boolean(followupOffer?.enabled) &&
(deps.isImplicitAddressContinuationByLlm(userMessage, llmPreDecomposeMeta) ||
(deps.toNonEmptyString(alternateMessage)
? deps.isImplicitAddressContinuationByLlm(alternateMessage, llmPreDecomposeMeta)
: false));
const sourceIntentHint = deps.toNonEmptyString(previousAddressDebug?.detected_intent);
const navigationFocusObjectHint = addressNavigationState &&
typeof addressNavigationState === "object" &&
addressNavigationState.session_context &&
typeof addressNavigationState.session_context === "object" &&
addressNavigationState.session_context.active_focus_object &&
typeof addressNavigationState.session_context.active_focus_object === "object"
? addressNavigationState.session_context.active_focus_object
: null;
const hasNavigationInventoryItemFocusHint = Boolean(deps.toNonEmptyString(navigationFocusObjectHint?.label) &&
deps.toNonEmptyString(navigationFocusObjectHint?.object_type) === "item" &&
(sourceIntentHint === "inventory_on_hand_as_of_date" ||
sourceIntentHint === "inventory_supplier_stock_overlap_as_of_date" ||
deps.isInventorySelectedObjectIntent(sourceIntentHint)));
let inventoryShortFollowupPrimary = (deps.isInventorySelectedObjectIntent(sourceIntentHint) || hasNavigationInventoryItemFocusHint) &&
deps.hasShortInventoryObjectFollowupSignal(userMessage);
let inventoryShortFollowupAlternate = (deps.isInventorySelectedObjectIntent(sourceIntentHint) || hasNavigationInventoryItemFocusHint) &&
deps.toNonEmptyString(alternateMessage)
? deps.hasShortInventoryObjectFollowupSignal(String(alternateMessage ?? ""))
: false;
const debtRoleSwapPrimary = sourceIntentHint
? deps.resolveDebtRoleSwapFollowupIntent(userMessage, sourceIntentHint)
: null;
const debtRoleSwapAlternate = sourceIntentHint && deps.toNonEmptyString(alternateMessage)
? deps.resolveDebtRoleSwapFollowupIntent(String(alternateMessage ?? ""), sourceIntentHint)
: null;
const debtRoleSwapIntent = debtRoleSwapPrimary ?? debtRoleSwapAlternate ?? null;
let hasPrimaryFollowupSignal = deps.hasAddressFollowupContextSignal(userMessage) || Boolean(debtRoleSwapPrimary) || inventoryShortFollowupPrimary;
let hasAlternateFollowupSignal = deps.toNonEmptyString(alternateMessage)
? deps.hasAddressFollowupContextSignal(alternateMessage) ||
Boolean(debtRoleSwapAlternate) ||
inventoryShortFollowupAlternate
: false;
const hasPrimaryIndexReferenceSignal = deps.extractDisplayedEntityIndexMention(userMessage) !== null;
const hasAlternateIndexReferenceSignal = deps.toNonEmptyString(alternateMessage)
? deps.extractDisplayedEntityIndexMention(String(alternateMessage ?? "")) !== null
: false;
const hasIndexReferenceSignal = hasPrimaryIndexReferenceSignal || hasAlternateIndexReferenceSignal;
const recentInventoryRootFrame = deps.findRecentInventoryRootFrame(items);
const hasInventoryRootTemporalFollowupPrimary = deps.hasInventoryRootTemporalFollowupSignal(userMessage, sourceIntentHint, Boolean(recentInventoryRootFrame));
const hasInventoryRootTemporalFollowupAlternate = deps.toNonEmptyString(alternateMessage)
? deps.hasInventoryRootTemporalFollowupSignal(String(alternateMessage ?? ""), sourceIntentHint, Boolean(recentInventoryRootFrame))
: false;
const hasInventoryRootRestatementPrimary = hasInventoryRootRestatementLikeSignal(userMessage, sourceIntentHint, Boolean(recentInventoryRootFrame));
const hasInventoryRootRestatementAlternate = deps.toNonEmptyString(alternateMessage)
? hasInventoryRootRestatementLikeSignal(String(alternateMessage ?? ""), sourceIntentHint, Boolean(recentInventoryRootFrame))
: false;
let hasStrongFollowupReference = hasPrimaryIndexReferenceSignal ||
hasAlternateIndexReferenceSignal ||
hasOrganizationClarificationContinuation ||
hasImplicitContinuationSignal ||
inventoryShortFollowupPrimary ||
inventoryShortFollowupAlternate ||
hasInventoryRootTemporalFollowupPrimary ||
hasInventoryRootTemporalFollowupAlternate ||
hasInventoryRootRestatementPrimary ||
hasInventoryRootRestatementAlternate ||
Boolean(debtRoleSwapIntent) ||
deps.hasFollowupMarker(userMessage) ||
deps.hasReferentialPointer(userMessage) ||
(deps.toNonEmptyString(alternateMessage)
? deps.hasFollowupMarker(String(alternateMessage ?? "")) ||
deps.hasReferentialPointer(String(alternateMessage ?? ""))
: false);
const hasStandaloneAddressTopic = deps.hasStandaloneAddressTopicSignal(userMessage) ||
(deps.toNonEmptyString(alternateMessage) ? deps.hasStandaloneAddressTopicSignal(alternateMessage) : false);
if (hasStandaloneAddressTopic &&
!hasPrimaryFollowupSignal &&
!hasAlternateFollowupSignal &&
!hasInventoryRootTemporalFollowupPrimary &&
!hasInventoryRootTemporalFollowupAlternate &&
!hasInventoryRootRestatementPrimary &&
!hasInventoryRootRestatementAlternate &&
!hasImplicitContinuationSignal &&
!hasOrganizationClarificationContinuation &&
!hasIndexReferenceSignal) {
return null;
}
if (!hasPrimaryFollowupSignal &&
!hasAlternateFollowupSignal &&
!hasInventoryRootTemporalFollowupPrimary &&
!hasInventoryRootTemporalFollowupAlternate &&
!hasInventoryRootRestatementPrimary &&
!hasInventoryRootRestatementAlternate &&
!hasImplicitContinuationSignal &&
!hasOrganizationClarificationContinuation &&
!hasIndexReferenceSignal) {
return null;
}
if (!previousAddressDebug) {
return null;
}
const sourceIntent = deps.toNonEmptyString(previousAddressDebug.detected_intent);
const llmExplicitIntent = deps.toNonEmptyString(llmPreDecomposeMeta?.predecomposeContract?.intent);
const resolvedPrimaryIntent = deps.resolveAddressIntent(deps.repairAddressMojibake(String(userMessage ?? ""))).intent;
const resolvedAlternateIntent = deps.toNonEmptyString(alternateMessage)
? deps.resolveAddressIntent(deps.repairAddressMojibake(String(alternateMessage ?? ""))).intent
: null;
const explicitIntent = llmExplicitIntent && llmExplicitIntent !== "unknown"
? llmExplicitIntent
: resolvedPrimaryIntent && resolvedPrimaryIntent !== "unknown"
? resolvedPrimaryIntent
: resolvedAlternateIntent && resolvedAlternateIntent !== "unknown"
? resolvedAlternateIntent
: null;
const sourceIntentFamily = deps.resolveAddressIntentFamily(sourceIntent);
const explicitIntentFamily = deps.resolveAddressIntentFamily(explicitIntent) ??
inferStandaloneAddressTopicFamily(userMessage) ??
(deps.toNonEmptyString(alternateMessage) ? inferStandaloneAddressTopicFamily(String(alternateMessage ?? "")) : null);
const foreignAccountingPivotOverInventory = deps.hasForeignAccountingPivotOverInventoryMessage(userMessage, alternateMessage);
const familyMismatchStandaloneTopic = Boolean(hasStandaloneAddressTopic &&
sourceIntentFamily &&
explicitIntentFamily &&
sourceIntentFamily !== explicitIntentFamily &&
!hasOrganizationClarificationContinuation &&
!hasImplicitContinuationSignal &&
!hasIndexReferenceSignal &&
!hasInventoryRootTemporalFollowupPrimary &&
!hasInventoryRootTemporalFollowupAlternate &&
!hasInventoryRootRestatementPrimary &&
!hasInventoryRootRestatementAlternate &&
!inventoryShortFollowupPrimary &&
!inventoryShortFollowupAlternate &&
!foreignAccountingPivotOverInventory &&
!deps.hasFollowupMarker(userMessage) &&
!deps.hasReferentialPointer(userMessage) &&
(!deps.toNonEmptyString(alternateMessage)
? true
: !deps.hasFollowupMarker(String(alternateMessage ?? "")) &&
!deps.hasReferentialPointer(String(alternateMessage ?? ""))));
if (familyMismatchStandaloneTopic) {
return null;
}
if (sourceIntentFamily &&
explicitIntentFamily &&
sourceIntentFamily !== explicitIntentFamily &&
!hasStrongFollowupReference &&
!foreignAccountingPivotOverInventory) {
return null;
}
let previousIntent = sourceIntent;
let followupSelectionMode = "carry_previous_intent";
if (debtRoleSwapIntent) {
previousIntent = debtRoleSwapIntent;
}
if (hasImplicitContinuationSignal) {
const suggestedIntent = Array.isArray(followupOffer?.suggested_intents)
? deps.toNonEmptyString(followupOffer.suggested_intents[0])
: null;
const keepPreviousIntent = shouldKeepPreviousIntentForShortCounterpartyRetargetV2(userMessage, sourceIntent);
if (suggestedIntent && !keepPreviousIntent) {
previousIntent = suggestedIntent;
followupSelectionMode = "switch_to_suggested_intent";
}
}
let previousAnchorType = deps.toNonEmptyString(previousAddressDebug.anchor_type);
let previousAnchor = deps.toNonEmptyString(previousAddressDebug.anchor_value_resolved) ??
deps.toNonEmptyString(previousAddressDebug.anchor_value_raw) ??
deps.readAddressFilterString(previousAddressDebug, "item") ??
deps.readAddressFilterString(previousAddressDebug, "counterparty") ??
deps.readAddressFilterString(previousAddressDebug, "account") ??
deps.readAddressFilterString(previousAddressDebug, "contract");
const navigationSessionContext = addressNavigationState && typeof addressNavigationState === "object"
? addressNavigationState.session_context && typeof addressNavigationState.session_context === "object"
? addressNavigationState.session_context
: null
: null;
const navigationDateScope = navigationSessionContext && typeof navigationSessionContext.date_scope === "object"
? navigationSessionContext.date_scope
: null;
const navigationOrganization = deps.normalizeOrganizationScopeValue(navigationSessionContext?.organization_scope);
const navigationFocusObject = navigationSessionContext && typeof navigationSessionContext.active_focus_object === "object"
? navigationSessionContext.active_focus_object
: null;
const navigationFocusObjectType = deps.toNonEmptyString(navigationFocusObject?.object_type);
const navigationFocusObjectLabel = deps.toNonEmptyString(navigationFocusObject?.label);
const hasInventoryItemFocusCarryover = navigationFocusObjectType === "item" &&
navigationFocusObjectLabel &&
(sourceIntentHint === "inventory_on_hand_as_of_date" ||
sourceIntentHint === "inventory_supplier_stock_overlap_as_of_date" ||
deps.isInventorySelectedObjectIntent(sourceIntentHint));
if (!inventoryShortFollowupPrimary && hasInventoryItemFocusCarryover) {
inventoryShortFollowupPrimary = deps.hasShortInventoryObjectFollowupSignal(userMessage);
}
if (!inventoryShortFollowupAlternate && hasInventoryItemFocusCarryover && deps.toNonEmptyString(alternateMessage)) {
inventoryShortFollowupAlternate = deps.hasShortInventoryObjectFollowupSignal(String(alternateMessage ?? ""));
}
hasPrimaryFollowupSignal =
deps.hasAddressFollowupContextSignal(userMessage) ||
Boolean(debtRoleSwapPrimary) ||
inventoryShortFollowupPrimary ||
hasInventoryRootTemporalFollowupPrimary;
hasAlternateFollowupSignal = deps.toNonEmptyString(alternateMessage)
? deps.hasAddressFollowupContextSignal(alternateMessage) ||
Boolean(debtRoleSwapAlternate) ||
inventoryShortFollowupAlternate ||
hasInventoryRootTemporalFollowupAlternate
: false;
hasStrongFollowupReference =
hasPrimaryIndexReferenceSignal ||
hasAlternateIndexReferenceSignal ||
hasOrganizationClarificationContinuation ||
hasImplicitContinuationSignal ||
inventoryShortFollowupPrimary ||
inventoryShortFollowupAlternate ||
hasInventoryRootTemporalFollowupPrimary ||
hasInventoryRootTemporalFollowupAlternate ||
Boolean(debtRoleSwapIntent) ||
deps.hasFollowupMarker(userMessage) ||
deps.hasReferentialPointer(userMessage) ||
(deps.toNonEmptyString(alternateMessage)
? deps.hasFollowupMarker(String(alternateMessage ?? "")) ||
deps.hasReferentialPointer(String(alternateMessage ?? ""))
: false);
const hasSelectedObjectInventorySignalPrimary = /(?:по\s+выбранному\s+объекту|по\s+этой\s+позиции|по\s+этому\s+товару|selected\s+object)/iu.test(String(userMessage ?? ""));
const hasSelectedObjectInventorySignalAlternate = deps.toNonEmptyString(alternateMessage)
? /(?:по\s+выбранному\s+объекту|по\s+этой\s+позиции|по\s+этому\s+товару|selected\s+object)/iu.test(String(alternateMessage ?? ""))
: false;
let inventoryRootFrame = deps.findRecentInventoryRootFrame(items);
if (inventoryRootFrame && navigationOrganization && !deps.toNonEmptyString(inventoryRootFrame.filters?.organization)) {
inventoryRootFrame = {
...inventoryRootFrame,
filters: {
...(inventoryRootFrame.filters ?? {}),
organization: navigationOrganization
}
};
}
if (inventoryRootFrame && navigationDateScope) {
inventoryRootFrame = {
...inventoryRootFrame,
filters: {
...(inventoryRootFrame.filters ?? {}),
as_of_date: deps.toNonEmptyString(inventoryRootFrame.filters?.as_of_date) ??
deps.toNonEmptyString(navigationDateScope.as_of_date) ??
undefined,
period_from: deps.toNonEmptyString(inventoryRootFrame.filters?.period_from) ??
deps.toNonEmptyString(navigationDateScope.period_from) ??
undefined,
period_to: deps.toNonEmptyString(inventoryRootFrame.filters?.period_to) ??
deps.toNonEmptyString(navigationDateScope.period_to) ??
undefined
}
};
}
let currentFrameKind = inventoryRootFrame
? deps.isInventoryDrilldownFrameIntent(sourceIntent)
? "inventory_drilldown"
: deps.isInventoryRootFrameIntent(sourceIntent)
? "inventory_root"
: "generic"
: null;
let resolvedCounterpartyFromDisplay = false;
let displayedEntityTargetIntent = null;
const previousFiltersRaw = previousAddressDebug.extracted_filters;
let previousFilters = previousFiltersRaw && typeof previousFiltersRaw === "object" ? { ...previousFiltersRaw } : {};
const shouldBackfillHistoricalPartyAnchors = sourceIntentHint === "list_contracts_by_counterparty" ||
sourceIntentHint === "list_documents_by_counterparty" ||
sourceIntentHint === "bank_operations_by_counterparty" ||
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;
}
}
if (!deps.toNonEmptyString(previousFilters.organization)) {
const historicalOrganization = deps.findRecentAddressFilterValue(items, "organization");
if (historicalOrganization) {
previousFilters.organization = historicalOrganization;
}
}
if (!deps.toNonEmptyString(previousFilters.organization) && navigationOrganization) {
previousFilters.organization = navigationOrganization;
}
if (!deps.toNonEmptyString(previousFilters.organization) && organizationClarificationSelection) {
previousFilters.organization = organizationClarificationSelection;
}
const shouldBackfillPreviousDateScopeFromNavigation = sourceIntentHint === "inventory_on_hand_as_of_date" ||
sourceIntentHint === "inventory_supplier_stock_overlap_as_of_date" ||
sourceIntentHint === "inventory_purchase_provenance_for_item" ||
sourceIntentHint === "inventory_purchase_documents_for_item" ||
sourceIntentHint === "inventory_sale_trace_for_item" ||
sourceIntentHint === "inventory_profitability_for_item" ||
sourceIntentHint === "inventory_purchase_to_sale_chain" ||
sourceIntentHint === "inventory_aging_by_purchase_date" ||
sourceIntentHint === "account_balance_snapshot" ||
sourceIntentHint === "documents_forming_balance";
if (shouldBackfillPreviousDateScopeFromNavigation &&
!deps.toNonEmptyString(previousFilters.as_of_date) &&
deps.toNonEmptyString(navigationDateScope?.as_of_date)) {
previousFilters.as_of_date = deps.toNonEmptyString(navigationDateScope?.as_of_date);
}
if (shouldBackfillPreviousDateScopeFromNavigation &&
!deps.toNonEmptyString(previousFilters.period_from) &&
deps.toNonEmptyString(navigationDateScope?.period_from)) {
previousFilters.period_from = deps.toNonEmptyString(navigationDateScope?.period_from);
}
if (shouldBackfillPreviousDateScopeFromNavigation &&
!deps.toNonEmptyString(previousFilters.period_to) &&
deps.toNonEmptyString(navigationDateScope?.period_to)) {
previousFilters.period_to = deps.toNonEmptyString(navigationDateScope?.period_to);
}
const rootContextOnlyPivot = Boolean((deps.isInventorySelectedObjectIntent(sourceIntentHint) || currentFrameKind === "inventory_drilldown") &&
deps.hasForeignAccountingPivotOverInventoryMessage(userMessage, alternateMessage));
const inventoryRootTemporalPivot = Boolean(inventoryRootFrame &&
(deps.isInventorySelectedObjectIntent(sourceIntentHint) ||
deps.isInventoryRootFrameIntent(sourceIntentHint) ||
currentFrameKind === "inventory_drilldown" ||
currentFrameKind === "inventory_root") &&
(hasInventoryRootTemporalFollowupPrimary || hasInventoryRootTemporalFollowupAlternate) &&
!deps.hasForeignAccountingPivotOverInventoryMessage(userMessage, alternateMessage));
const inventoryRootRestatementPivot = Boolean(inventoryRootFrame &&
(deps.isInventorySelectedObjectIntent(sourceIntentHint) ||
deps.isInventoryRootFrameIntent(sourceIntentHint) ||
currentFrameKind === "inventory_drilldown" ||
currentFrameKind === "inventory_root" ||
currentFrameKind === "generic") &&
(hasInventoryRootRestatementPrimary || hasInventoryRootRestatementAlternate) &&
!deps.hasForeignAccountingPivotOverInventoryMessage(userMessage, alternateMessage));
const rootScopedPivot = rootContextOnlyPivot || inventoryRootTemporalPivot || inventoryRootRestatementPivot;
if (rootScopedPivot) {
previousIntent = null;
previousAnchorType = null;
previousAnchor = null;
previousFilters = deps.buildRootScopedCarryoverFilters(previousFilters, inventoryRootFrame);
currentFrameKind = inventoryRootFrame ? "inventory_root" : currentFrameKind;
followupSelectionMode = "carry_root_context";
}
const displayedEntityType = deps.inferDisplayedEntityTypeFromIntent(sourceIntent);
const displayedEntities = deps.extractDisplayedAddressEntityCandidates(deps.toNonEmptyString(previousAddressItem?.text) ?? "", displayedEntityType);
const resolvedEntityFromFollowup = deps.resolveDisplayedAddressEntityMention(userMessage, displayedEntities) ??
(deps.toNonEmptyString(alternateMessage)
? deps.resolveDisplayedAddressEntityMention(String(alternateMessage ?? ""), displayedEntities)
: null);
if (resolvedEntityFromFollowup && !rootScopedPivot) {
displayedEntityTargetIntent = resolveDisplayedEntityRetargetIntent(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";
}
}
if (!rootScopedPivot &&
!deps.toNonEmptyString(previousFilters.item) &&
navigationFocusObjectType === "item" &&
navigationFocusObjectLabel &&
(sourceIntentHint === "inventory_on_hand_as_of_date" ||
sourceIntentHint === "inventory_purchase_provenance_for_item" ||
sourceIntentHint === "inventory_purchase_documents_for_item" ||
sourceIntentHint === "inventory_sale_trace_for_item" ||
sourceIntentHint === "inventory_profitability_for_item" ||
sourceIntentHint === "inventory_purchase_to_sale_chain" ||
sourceIntentHint === "inventory_aging_by_purchase_date" ||
hasSelectedObjectInventorySignalPrimary ||
hasSelectedObjectInventorySignalAlternate)) {
previousFilters.item = navigationFocusObjectLabel;
if (!previousAnchor) {
previousAnchorType = "item";
previousAnchor = navigationFocusObjectLabel;
}
}
if (organizationClarificationSelection && !previousAnchor) {
previousAnchorType = "organization";
previousAnchor = organizationClarificationSelection;
}
if (inventoryRootFrame &&
organizationClarificationSelection &&
!deps.toNonEmptyString(inventoryRootFrame.filters?.organization)) {
inventoryRootFrame = {
...inventoryRootFrame,
filters: {
...(inventoryRootFrame.filters ?? {}),
organization: organizationClarificationSelection
}
};
}
if (!previousIntent && !previousAnchor && Object.keys(previousFilters).length === 0) {
return null;
}
const shouldAttachInventoryRootFrame = Boolean(inventoryRootFrame &&
(rootScopedPivot ||
deps.isInventoryRootFrameIntent(sourceIntentHint) ||
deps.isInventorySelectedObjectIntent(sourceIntentHint) ||
hasNavigationInventoryItemFocusHint ||
inventoryShortFollowupPrimary ||
inventoryShortFollowupAlternate ||
hasInventoryRootTemporalFollowupPrimary ||
hasInventoryRootTemporalFollowupAlternate ||
hasInventoryRootRestatementPrimary ||
hasInventoryRootRestatementAlternate ||
hasSelectedObjectInventorySignalPrimary ||
hasSelectedObjectInventorySignalAlternate));
const carryoverTargetIntent = followupSelectionMode === "carry_root_context"
? inventoryRootFrame?.intent ?? displayedEntityTargetIntent ?? explicitIntent ?? previousIntent ?? undefined
: displayedEntityTargetIntent ?? explicitIntent ?? previousIntent ?? undefined;
return {
followupContext: {
previous_intent: previousIntent ?? undefined,
target_intent: carryoverTargetIntent,
previous_filters: previousFilters,
previous_anchor_type: previousAnchorType ?? undefined,
previous_anchor_value: previousAnchor,
resolved_counterparty_from_display: resolvedCounterpartyFromDisplay || undefined,
root_context_only: rootScopedPivot || undefined,
root_intent: shouldAttachInventoryRootFrame ? inventoryRootFrame?.intent ?? undefined : undefined,
root_filters: shouldAttachInventoryRootFrame ? inventoryRootFrame?.filters ?? undefined : undefined,
root_anchor_type: shouldAttachInventoryRootFrame ? inventoryRootFrame?.anchorType ?? undefined : undefined,
root_anchor_value: shouldAttachInventoryRootFrame ? inventoryRootFrame?.anchorValue ?? undefined : undefined,
current_frame_kind: shouldAttachInventoryRootFrame ? currentFrameKind ?? undefined : undefined
},
previousAddressIntent: previousIntent,
previousAddressAnchor: previousAnchor,
previousSourceIntent: sourceIntent,
followupSelectionMode,
hasImplicitContinuationSignal
};
}
function buildAddressDialogContinuationContractV2(userMessage, effectiveMessage, carryoverMeta, llmPreDecomposeMeta) {
const sourceMessage = String(userMessage ?? "");
const canonicalMessage = String(effectiveMessage ?? sourceMessage);
const hasFollowupContext = Boolean(carryoverMeta?.followupContext);
const previousIntent = deps.toNonEmptyString(carryoverMeta?.previousSourceIntent) ?? null;
const selectionMode = deps.toNonEmptyString(carryoverMeta?.followupSelectionMode) ?? null;
const rootContextOnly = selectionMode === "carry_root_context";
const carryoverTargetIntent = deps.toNonEmptyString(carryoverMeta?.followupContext?.target_intent) ?? null;
const explicitIntentRaw = deps.toNonEmptyString(llmPreDecomposeMeta?.predecomposeContract?.intent);
const explicitIntent = explicitIntentRaw === "unknown" ? null : explicitIntentRaw;
const rootIntent = deps.toNonEmptyString(carryoverMeta?.followupContext?.root_intent) ?? null;
const targetIntent = selectionMode === "switch_to_suggested_intent"
? deps.toNonEmptyString(carryoverMeta?.previousAddressIntent) ?? null
: rootContextOnly
? carryoverTargetIntent ?? rootIntent ?? explicitIntent ?? null
: carryoverTargetIntent ?? explicitIntent ?? deps.toNonEmptyString(carryoverMeta?.previousAddressIntent) ?? null;
const hasImplicitContinuationSignal = Boolean(carryoverMeta?.hasImplicitContinuationSignal);
const rewrittenByPredecompose = deps.compactWhitespace(sourceMessage.toLowerCase()) !== deps.compactWhitespace(canonicalMessage.toLowerCase());
const hasExplicitIntent = Boolean(explicitIntent);
const decision = !hasFollowupContext
? "new_topic"
: selectionMode === "switch_to_suggested_intent"
? "switch_to_suggested"
: "continue_previous";
const reasons = [];
if (hasFollowupContext) {
reasons.push("followup_context_detected");
}
if (hasImplicitContinuationSignal) {
reasons.push("implicit_continuation_by_llm");
}
if (rewrittenByPredecompose) {
reasons.push("effective_message_rewritten_by_predecompose");
}
if (hasExplicitIntent) {
reasons.push("llm_contract_intent_available");
}
if (selectionMode === "carry_referenced_entity" && explicitIntent && previousIntent && explicitIntent !== previousIntent) {
reasons.push("operation_intent_from_current_message");
}
if (rootContextOnly) {
reasons.push("root_context_only_carryover");
}
return {
schema_version: "address_dialog_continuation_contract_v2",
source_message: sourceMessage,
effective_message: canonicalMessage,
decision,
decision_reasons: reasons,
followup_context_applied: hasFollowupContext,
previous_intent: previousIntent,
target_intent: targetIntent,
intent_selection_mode: selectionMode,
anchor_type: carryoverMeta?.followupContext?.previous_anchor_type ?? null,
anchor_value: carryoverMeta?.followupContext?.previous_anchor_value ?? null,
implicit_continuation_signal: hasImplicitContinuationSignal
};
}
return {
resolveAddressFollowupCarryoverContext,
buildAddressDialogContinuationContractV2
};
}