АРЧ АП11 - Вынести transition carryover policy из assistantService в отдельный модуль
This commit is contained in:
+37
-2
@@ -69,6 +69,7 @@ const assistantDeepTurnAttemptRuntimeAdapter_1 = __importStar(require("./assista
|
||||
const assistantBoundaryPolicy_1 = __importStar(require("./assistantBoundaryPolicy"));
|
||||
const assistantLivingModePolicy_1 = __importStar(require("./assistantLivingModePolicy"));
|
||||
const assistantRoutePolicy_1 = __importStar(require("./assistantRoutePolicy"));
|
||||
const assistantTransitionPolicy_1 = __importStar(require("./assistantTransitionPolicy"));
|
||||
const assistantOrganizationScopeRuntimeAdapter_1 = __importStar(require("./assistantOrganizationScopeRuntimeAdapter"));
|
||||
const assistantTurnAttemptRuntimeAdapter_1 = __importStar(require("./assistantTurnAttemptRuntimeAdapter"));
|
||||
const assistantTurnRuntimeDepsAdapter_1 = __importStar(require("./assistantTurnRuntimeDepsAdapter"));
|
||||
@@ -4790,6 +4791,40 @@ const assistantRoutePolicy = (0, assistantRoutePolicy_1.createAssistantRoutePoli
|
||||
hasDeepSessionContinuationSignal,
|
||||
resolveLivingAssistantModeDecision: assistantLivingModePolicy.resolveLivingAssistantModeDecision
|
||||
});
|
||||
const assistantTransitionPolicy = (0, assistantTransitionPolicy_1.createAssistantTransitionPolicy)({
|
||||
compactWhitespace,
|
||||
repairAddressMojibake,
|
||||
countTokens,
|
||||
findLastAddressAssistantItem,
|
||||
findLastOrganizationClarificationAddressDebug,
|
||||
mergeKnownOrganizations,
|
||||
resolveOrganizationSelectionFromMessage,
|
||||
toNonEmptyString,
|
||||
buildAddressFollowupOffer,
|
||||
isImplicitAddressContinuationByLlm,
|
||||
isInventorySelectedObjectIntent,
|
||||
hasShortInventoryObjectFollowupSignal,
|
||||
resolveDebtRoleSwapFollowupIntent,
|
||||
hasAddressFollowupContextSignal,
|
||||
extractDisplayedEntityIndexMention,
|
||||
findRecentInventoryRootFrame,
|
||||
hasInventoryRootTemporalFollowupSignal,
|
||||
hasFollowupMarker,
|
||||
hasReferentialPointer,
|
||||
hasStandaloneAddressTopicSignal,
|
||||
resolveAddressIntent: addressIntentResolver_1.resolveAddressIntent,
|
||||
resolveAddressIntentFamily,
|
||||
readAddressFilterString,
|
||||
normalizeOrganizationScopeValue,
|
||||
isInventoryDrilldownFrameIntent,
|
||||
isInventoryRootFrameIntent,
|
||||
findRecentAddressFilterValue,
|
||||
hasForeignAccountingPivotOverInventoryMessage,
|
||||
buildRootScopedCarryoverFilters,
|
||||
inferDisplayedEntityTypeFromIntent,
|
||||
extractDisplayedAddressEntityCandidates,
|
||||
resolveDisplayedAddressEntityMention
|
||||
});
|
||||
function normalizeOrganizationScopeSearchText(value) {
|
||||
const source = normalizeScopeKey(value);
|
||||
return source
|
||||
@@ -5643,9 +5678,9 @@ class AssistantService {
|
||||
buildAddressLlmPredecomposeContractV1: predecomposeContract_1.buildAddressLlmPredecomposeContractV1,
|
||||
sanitizeAddressMessageForFallback,
|
||||
toNonEmptyString,
|
||||
resolveAddressFollowupCarryoverContext,
|
||||
resolveAddressFollowupCarryoverContext: assistantTransitionPolicy.resolveAddressFollowupCarryoverContext,
|
||||
resolveAssistantOrchestrationDecision,
|
||||
buildAddressDialogContinuationContractV2,
|
||||
buildAddressDialogContinuationContractV2: assistantTransitionPolicy.buildAddressDialogContinuationContractV2,
|
||||
mergeFollowupContextWithOrganizationScope,
|
||||
isRetryableAddressLimitedResult,
|
||||
mergeKnownOrganizations,
|
||||
|
||||
@@ -0,0 +1,487 @@
|
||||
"use strict";
|
||||
// @ts-nocheck
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.createAssistantTransitionPolicy = createAssistantTransitionPolicy;
|
||||
function createAssistantTransitionPolicy(deps) {
|
||||
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 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;
|
||||
let 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 hasStandaloneAddressTopic = deps.hasStandaloneAddressTopicSignal(userMessage) ||
|
||||
(deps.toNonEmptyString(alternateMessage) ? deps.hasStandaloneAddressTopicSignal(alternateMessage) : false);
|
||||
if (hasStandaloneAddressTopic &&
|
||||
!hasPrimaryFollowupSignal &&
|
||||
!hasAlternateFollowupSignal &&
|
||||
!hasInventoryRootTemporalFollowupPrimary &&
|
||||
!hasInventoryRootTemporalFollowupAlternate &&
|
||||
!hasImplicitContinuationSignal &&
|
||||
!hasOrganizationClarificationContinuation &&
|
||||
!hasIndexReferenceSignal) {
|
||||
return null;
|
||||
}
|
||||
if (!hasPrimaryFollowupSignal &&
|
||||
!hasAlternateFollowupSignal &&
|
||||
!hasInventoryRootTemporalFollowupPrimary &&
|
||||
!hasInventoryRootTemporalFollowupAlternate &&
|
||||
!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);
|
||||
if (sourceIntentFamily && explicitIntentFamily && sourceIntentFamily !== explicitIntentFamily && !hasStrongFollowupReference) {
|
||||
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 = shouldKeepPreviousIntentForShortCounterpartyRetarget(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;
|
||||
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 rootScopedPivot = rootContextOnlyPivot || inventoryRootTemporalPivot;
|
||||
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) {
|
||||
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 ||
|
||||
hasSelectedObjectInventorySignalPrimary ||
|
||||
hasSelectedObjectInventorySignalAlternate));
|
||||
const carryoverTargetIntent = followupSelectionMode === "carry_root_context"
|
||||
? inventoryRootFrame?.intent ?? explicitIntent ?? previousIntent ?? undefined
|
||||
: 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 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
|
||||
? rootIntent ?? explicitIntent ?? null
|
||||
: 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
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user