Архитектура: централизовать inventory root-frame state и root-scoped carryover в continuity policy

This commit is contained in:
2026-04-19 09:25:22 +03:00
parent c9730c986a
commit 46dfef6fb6
9 changed files with 297 additions and 132 deletions
@@ -9,6 +9,8 @@ exports.readAddressDebugTemporalScope = readAddressDebugTemporalScope;
exports.resolveAddressDebugAnchorContext = resolveAddressDebugAnchorContext;
exports.resolveAddressDebugContextFacts = resolveAddressDebugContextFacts;
exports.resolveAddressDebugCarryoverFilters = resolveAddressDebugCarryoverFilters;
exports.hydrateInventoryRootFrameState = hydrateInventoryRootFrameState;
exports.buildRootScopedCarryoverFilters = buildRootScopedCarryoverFilters;
exports.buildInventoryRootFrameFromAddressDebug = buildInventoryRootFrameFromAddressDebug;
exports.isGroundedAddressDebug = isGroundedAddressDebug;
exports.resolveAssistantContinuitySnapshot = resolveAssistantContinuitySnapshot;
@@ -153,6 +155,84 @@ function resolveAddressDebugCarryoverFilters(debug, toNonEmptyString = fallbackT
}
return nextFilters;
}
function hydrateInventoryRootFrameState(inventoryRootFrame, sourceIntent, navigationOrganization, navigationDateScope, toNonEmptyString = fallbackToNonEmptyString, isInventoryDrilldownFrameIntent = () => false, isInventoryRootFrameIntent = () => false) {
if (!inventoryRootFrame) {
return { inventoryRootFrame: null, currentFrameKind: null };
}
let hydratedRootFrame = {
...inventoryRootFrame,
filters: {
...(inventoryRootFrame.filters ?? {})
},
currentFrameKind: toNonEmptyString(inventoryRootFrame.currentFrameKind) ?? null
};
if (navigationOrganization && !toNonEmptyString(hydratedRootFrame.filters?.organization)) {
hydratedRootFrame = {
...hydratedRootFrame,
filters: {
...(hydratedRootFrame.filters ?? {}),
organization: navigationOrganization
}
};
}
if (navigationDateScope) {
hydratedRootFrame = {
...hydratedRootFrame,
filters: {
...(hydratedRootFrame.filters ?? {}),
as_of_date: toNonEmptyString(hydratedRootFrame.filters?.as_of_date) ??
toNonEmptyString(navigationDateScope.as_of_date) ??
undefined,
period_from: toNonEmptyString(hydratedRootFrame.filters?.period_from) ??
toNonEmptyString(navigationDateScope.period_from) ??
undefined,
period_to: toNonEmptyString(hydratedRootFrame.filters?.period_to) ??
toNonEmptyString(navigationDateScope.period_to) ??
undefined
}
};
}
const currentFrameKind = toNonEmptyString(hydratedRootFrame.currentFrameKind) ??
(isInventoryDrilldownFrameIntent(sourceIntent)
? "inventory_drilldown"
: isInventoryRootFrameIntent(sourceIntent)
? "inventory_root"
: "generic");
return {
inventoryRootFrame: {
...hydratedRootFrame,
currentFrameKind
},
currentFrameKind
};
}
function buildRootScopedCarryoverFilters(previousFilters, inventoryRootFrame, toNonEmptyString = fallbackToNonEmptyString) {
const candidateFilters = inventoryRootFrame?.filters && typeof inventoryRootFrame.filters === "object"
? inventoryRootFrame.filters
: {};
const nextFilters = {};
const organization = toNonEmptyString(candidateFilters?.organization) ?? toNonEmptyString(previousFilters?.organization);
const warehouse = toNonEmptyString(candidateFilters?.warehouse) ?? toNonEmptyString(previousFilters?.warehouse);
const asOfDate = toNonEmptyString(previousFilters?.as_of_date) ?? toNonEmptyString(candidateFilters?.as_of_date);
const periodFrom = toNonEmptyString(previousFilters?.period_from) ?? toNonEmptyString(candidateFilters?.period_from);
const periodTo = toNonEmptyString(previousFilters?.period_to) ?? toNonEmptyString(candidateFilters?.period_to);
if (organization) {
nextFilters.organization = organization;
}
if (warehouse) {
nextFilters.warehouse = warehouse;
}
if (asOfDate) {
nextFilters.as_of_date = asOfDate;
}
if (periodFrom) {
nextFilters.period_from = periodFrom;
}
if (periodTo) {
nextFilters.period_to = periodTo;
}
return nextFilters;
}
function buildInventoryRootFrameFromAddressDebug(debug, toNonEmptyString = fallbackToNonEmptyString) {
if (!debug || typeof debug !== "object") {
return null;
+1 -29
View File
@@ -41,7 +41,6 @@ exports.evaluateCoverageForTests = evaluateCoverageForTests;
exports.extractSubjectTokensForTests = extractSubjectTokensForTests;
exports.resolveAssistantOrchestrationDecision = resolveAssistantOrchestrationDecision;
exports.resolveSessionOrganizationScopeContextForTests = resolveSessionOrganizationScopeContextForTests;
exports.buildRootScopedCarryoverFiltersForTests = buildRootScopedCarryoverFiltersForTests;
exports.extractOrganizationFactsFromRowsForTests = extractOrganizationFactsFromRowsForTests;
exports.resolveOrganizationNamesByRefsForTests = resolveOrganizationNamesByRefsForTests;
exports.resolveLivingAssistantModeDecision = resolveLivingAssistantModeDecision;
@@ -2758,31 +2757,7 @@ function hasForeignAccountingPivotOverInventoryMessage(userMessage, alternateMes
/(?:оплат|плат(?:е|ё)ж|аванс|зач(?:е|ё)т|выписк|statement|wire|settlement|payment|\b51(?:\.\d{1,2})?\b|\b60(?:\.\d{1,2})?\b|\b62(?:\.\d{1,2})?\b)/iu.test(sample));
}
function buildRootScopedCarryoverFilters(previousFilters, inventoryRootFrame) {
const candidateFilters = inventoryRootFrame?.filters && typeof inventoryRootFrame.filters === "object"
? inventoryRootFrame.filters
: {};
const nextFilters = {};
const organization = toNonEmptyString(candidateFilters?.organization) ?? toNonEmptyString(previousFilters?.organization);
const warehouse = toNonEmptyString(candidateFilters?.warehouse) ?? toNonEmptyString(previousFilters?.warehouse);
const asOfDate = toNonEmptyString(previousFilters?.as_of_date) ?? toNonEmptyString(candidateFilters?.as_of_date);
const periodFrom = toNonEmptyString(previousFilters?.period_from) ?? toNonEmptyString(candidateFilters?.period_from);
const periodTo = toNonEmptyString(previousFilters?.period_to) ?? toNonEmptyString(candidateFilters?.period_to);
if (organization) {
nextFilters.organization = organization;
}
if (warehouse) {
nextFilters.warehouse = warehouse;
}
if (asOfDate) {
nextFilters.as_of_date = asOfDate;
}
if (periodFrom) {
nextFilters.period_from = periodFrom;
}
if (periodTo) {
nextFilters.period_to = periodTo;
}
return nextFilters;
return (0, assistantContinuityPolicy_1.buildRootScopedCarryoverFilters)(previousFilters, inventoryRootFrame, toNonEmptyString);
}
function resolveDebtRoleSwapFollowupIntent(userMessage, previousIntent) {
const normalized = compactWhitespace(String(userMessage ?? "").toLowerCase());
@@ -4573,9 +4548,6 @@ function mergeFollowupContextWithOrganizationScope(followupContext, organization
function resolveSessionOrganizationScopeContextForTests(userMessage, items, addressNavigationState = null) {
return resolveSessionOrganizationScopeContext(userMessage, items, addressNavigationState);
}
function buildRootScopedCarryoverFiltersForTests(previousFilters, inventoryRootFrame) {
return buildRootScopedCarryoverFilters(previousFilters, inventoryRootFrame);
}
function normalizeGuidValue(value) {
const source = normalizeScopeLabel(value);
if (!source) {
@@ -589,42 +589,10 @@ function createAssistantTransitionPolicy(deps) {
const selectedObjectRetargetIntent = hasSelectedObjectInventorySignalPrimary || hasSelectedObjectInventorySignalAlternate
? inferSelectedObjectInventoryFollowupIntent(userMessage, alternateMessage)
: null;
let inventoryRootFrame = deps.findRecentInventoryRootFrame(items) ??
const inventoryRootFrameCandidate = deps.findRecentInventoryRootFrame(items) ??
continuitySnapshot.inventoryRootFrame ??
(0, assistantContinuityPolicy_1.buildInventoryRootFrameFromAddressDebug)(continuitySnapshot.lastGroundedAddressDebug, deps.toNonEmptyString);
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 { inventoryRootFrame, currentFrameKind } = (0, assistantContinuityPolicy_1.hydrateInventoryRootFrameState)(inventoryRootFrameCandidate, sourceIntent, navigationOrganization, navigationDateScope, deps.toNonEmptyString, deps.isInventoryDrilldownFrameIntent, deps.isInventoryRootFrameIntent);
let resolvedCounterpartyFromDisplay = false;
let displayedEntityTargetIntent = null;
let previousFilters = (0, assistantContinuityPolicy_1.resolveAddressDebugCarryoverFilters)(previousAddressDebug, deps.toNonEmptyString);
@@ -745,7 +713,7 @@ function createAssistantTransitionPolicy(deps) {
previousIntent = null;
previousAnchorType = null;
previousAnchor = null;
previousFilters = deps.buildRootScopedCarryoverFilters(previousFilters, inventoryRootFrame);
previousFilters = (0, assistantContinuityPolicy_1.buildRootScopedCarryoverFilters)(previousFilters, inventoryRootFrame, deps.toNonEmptyString);
currentFrameKind = inventoryRootFrame ? "inventory_root" : currentFrameKind;
followupSelectionMode = "carry_root_context";
}