Архитектура: централизовать navigation focus authority в continuity policy и сделать phase15 replay time-stable
This commit is contained in:
@@ -7,6 +7,7 @@ exports.readAddressDebugOrganization = readAddressDebugOrganization;
|
||||
exports.readAddressDebugScopedDate = readAddressDebugScopedDate;
|
||||
exports.readAddressDebugTemporalScope = readAddressDebugTemporalScope;
|
||||
exports.resolveAddressDebugAnchorContext = resolveAddressDebugAnchorContext;
|
||||
exports.resolveNavigationSessionContextState = resolveNavigationSessionContextState;
|
||||
exports.resolveAddressDebugContextFacts = resolveAddressDebugContextFacts;
|
||||
exports.resolveAddressDebugCarryoverFilters = resolveAddressDebugCarryoverFilters;
|
||||
exports.hydrateInventoryRootFrameState = hydrateInventoryRootFrameState;
|
||||
@@ -127,6 +128,23 @@ function resolveAddressDebugAnchorContext(debug, toNonEmptyString = fallbackToNo
|
||||
anchorValue: null
|
||||
};
|
||||
}
|
||||
function resolveNavigationSessionContextState(addressNavigationState, toNonEmptyString = fallbackToNonEmptyString, normalizeOrganizationScopeValue = normalizeOrganizationScopeDefault) {
|
||||
const sessionContext = toRecordObject(toRecordObject(addressNavigationState)?.session_context);
|
||||
const rawFocusObject = toRecordObject(sessionContext?.active_focus_object);
|
||||
const focusObject = rawFocusObject
|
||||
? {
|
||||
objectType: toNonEmptyString(rawFocusObject.object_type),
|
||||
label: toNonEmptyString(rawFocusObject.label),
|
||||
provenanceResultSetId: toNonEmptyString(rawFocusObject.provenance_result_set_id)
|
||||
}
|
||||
: null;
|
||||
return {
|
||||
dateScope: toRecordObject(sessionContext?.date_scope),
|
||||
organization: normalizeOrganizationScopeValue(sessionContext?.organization_scope),
|
||||
focusObject,
|
||||
activeResultSetId: toNonEmptyString(sessionContext?.active_result_set_id)
|
||||
};
|
||||
}
|
||||
function resolveAddressDebugContextFacts(debug, toNonEmptyString = fallbackToNonEmptyString) {
|
||||
return {
|
||||
item: readAddressDebugItem(debug, toNonEmptyString),
|
||||
|
||||
@@ -104,17 +104,9 @@ function createAssistantTransitionPolicy(deps) {
|
||||
return computeMonthWindowFromIso(explicitFirstDateIso);
|
||||
}
|
||||
}
|
||||
const sessionContext = addressNavigationState &&
|
||||
typeof addressNavigationState === "object" &&
|
||||
addressNavigationState.session_context &&
|
||||
typeof addressNavigationState.session_context === "object"
|
||||
? addressNavigationState.session_context
|
||||
: null;
|
||||
const focusObject = sessionContext && typeof sessionContext.active_focus_object === "object"
|
||||
? sessionContext.active_focus_object
|
||||
: null;
|
||||
const preferredResultSetId = deps.toNonEmptyString(focusObject?.provenance_result_set_id) ??
|
||||
deps.toNonEmptyString(sessionContext?.active_result_set_id);
|
||||
const navigationSessionState = (0, assistantContinuityPolicy_1.resolveNavigationSessionContextState)(addressNavigationState, deps.toNonEmptyString, deps.normalizeOrganizationScopeValue);
|
||||
const focusObject = navigationSessionState.focusObject;
|
||||
const preferredResultSetId = deps.toNonEmptyString(focusObject?.provenanceResultSetId) ?? navigationSessionState.activeResultSetId;
|
||||
const resultSets = Array.isArray(addressNavigationState?.result_sets) ? addressNavigationState.result_sets : [];
|
||||
const preferredResultSet = (preferredResultSetId
|
||||
? resultSets.find((item) => deps.toNonEmptyString(item?.result_set_id) === preferredResultSetId) ?? null
|
||||
@@ -331,16 +323,10 @@ function createAssistantTransitionPolicy(deps) {
|
||||
? deps.isImplicitAddressContinuationByLlm(alternateMessage, llmPreDecomposeMeta)
|
||||
: false));
|
||||
const sourceIntentHint = deps.toNonEmptyString(carryoverSourceDebug?.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 navigationSessionState = (0, assistantContinuityPolicy_1.resolveNavigationSessionContextState)(addressNavigationState, deps.toNonEmptyString, deps.normalizeOrganizationScopeValue);
|
||||
const navigationFocusObjectHint = navigationSessionState.focusObject;
|
||||
const hasNavigationInventoryItemFocusHint = Boolean(deps.toNonEmptyString(navigationFocusObjectHint?.label) &&
|
||||
deps.toNonEmptyString(navigationFocusObjectHint?.object_type) === "item" &&
|
||||
deps.toNonEmptyString(navigationFocusObjectHint?.objectType) === "item" &&
|
||||
(sourceIntentHint === "inventory_on_hand_as_of_date" ||
|
||||
sourceIntentHint === "inventory_supplier_stock_overlap_as_of_date" ||
|
||||
deps.isInventorySelectedObjectIntent(sourceIntentHint)));
|
||||
@@ -499,19 +485,10 @@ function createAssistantTransitionPolicy(deps) {
|
||||
const previousAnchorContext = (0, assistantContinuityPolicy_1.resolveAddressDebugAnchorContext)(carryoverSourceDebug, deps.toNonEmptyString);
|
||||
let previousAnchorType = previousAnchorContext.anchorType;
|
||||
let previousAnchor = previousAnchorContext.anchorValue;
|
||||
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 navigationDateScope = navigationSessionState.dateScope;
|
||||
const navigationOrganization = navigationSessionState.organization;
|
||||
const navigationFocusObject = navigationSessionState.focusObject;
|
||||
const navigationFocusObjectType = deps.toNonEmptyString(navigationFocusObject?.objectType);
|
||||
const navigationFocusObjectLabel = deps.toNonEmptyString(navigationFocusObject?.label);
|
||||
const hasInventoryItemFocusCarryover = navigationFocusObjectType === "item" &&
|
||||
navigationFocusObjectLabel &&
|
||||
|
||||
@@ -45,6 +45,19 @@ export interface AssistantNavigationDateScope {
|
||||
period_to?: unknown;
|
||||
}
|
||||
|
||||
export interface AssistantNavigationFocusObject {
|
||||
objectType: string | null;
|
||||
label: string | null;
|
||||
provenanceResultSetId: string | null;
|
||||
}
|
||||
|
||||
export interface AssistantNavigationSessionContextState {
|
||||
dateScope: AssistantNavigationDateScope | null;
|
||||
organization: string | null;
|
||||
focusObject: AssistantNavigationFocusObject | null;
|
||||
activeResultSetId: string | null;
|
||||
}
|
||||
|
||||
export interface AssistantAddressDebugAnchorContext {
|
||||
anchorType: string | null;
|
||||
anchorValue: string | null;
|
||||
@@ -203,6 +216,28 @@ export function resolveAddressDebugAnchorContext(
|
||||
};
|
||||
}
|
||||
|
||||
export function resolveNavigationSessionContextState(
|
||||
addressNavigationState: unknown,
|
||||
toNonEmptyString: (value: unknown) => string | null = fallbackToNonEmptyString,
|
||||
normalizeOrganizationScopeValue: (value: unknown) => string | null = normalizeOrganizationScopeDefault
|
||||
): AssistantNavigationSessionContextState {
|
||||
const sessionContext = toRecordObject(toRecordObject(addressNavigationState)?.session_context);
|
||||
const rawFocusObject = toRecordObject(sessionContext?.active_focus_object);
|
||||
const focusObject = rawFocusObject
|
||||
? {
|
||||
objectType: toNonEmptyString(rawFocusObject.object_type),
|
||||
label: toNonEmptyString(rawFocusObject.label),
|
||||
provenanceResultSetId: toNonEmptyString(rawFocusObject.provenance_result_set_id)
|
||||
}
|
||||
: null;
|
||||
return {
|
||||
dateScope: toRecordObject(sessionContext?.date_scope) as AssistantNavigationDateScope | null,
|
||||
organization: normalizeOrganizationScopeValue(sessionContext?.organization_scope),
|
||||
focusObject,
|
||||
activeResultSetId: toNonEmptyString(sessionContext?.active_result_set_id)
|
||||
};
|
||||
}
|
||||
|
||||
export function resolveAddressDebugContextFacts(
|
||||
debug: Record<string, unknown> | null,
|
||||
toNonEmptyString: (value: unknown) => string | null = fallbackToNonEmptyString
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
readAddressDebugFilters,
|
||||
readAddressDebugItem,
|
||||
readAddressDebugTemporalScope,
|
||||
resolveNavigationSessionContextState,
|
||||
resolveAddressDebugCarryoverFilters,
|
||||
resolveAddressDebugAnchorContext,
|
||||
resolveDisplayedEntityFollowupRetarget,
|
||||
@@ -145,20 +146,14 @@ export function createAssistantTransitionPolicy(deps) {
|
||||
}
|
||||
}
|
||||
|
||||
const sessionContext =
|
||||
addressNavigationState &&
|
||||
typeof addressNavigationState === "object" &&
|
||||
addressNavigationState.session_context &&
|
||||
typeof addressNavigationState.session_context === "object"
|
||||
? addressNavigationState.session_context
|
||||
: null;
|
||||
const focusObject =
|
||||
sessionContext && typeof sessionContext.active_focus_object === "object"
|
||||
? sessionContext.active_focus_object
|
||||
: null;
|
||||
const navigationSessionState = resolveNavigationSessionContextState(
|
||||
addressNavigationState,
|
||||
deps.toNonEmptyString,
|
||||
deps.normalizeOrganizationScopeValue
|
||||
);
|
||||
const focusObject = navigationSessionState.focusObject;
|
||||
const preferredResultSetId =
|
||||
deps.toNonEmptyString(focusObject?.provenance_result_set_id) ??
|
||||
deps.toNonEmptyString(sessionContext?.active_result_set_id);
|
||||
deps.toNonEmptyString(focusObject?.provenanceResultSetId) ?? navigationSessionState.activeResultSetId;
|
||||
const resultSets = Array.isArray(addressNavigationState?.result_sets) ? addressNavigationState.result_sets : [];
|
||||
const preferredResultSet =
|
||||
(preferredResultSetId
|
||||
@@ -431,18 +426,15 @@ export function createAssistantTransitionPolicy(deps) {
|
||||
? deps.isImplicitAddressContinuationByLlm(alternateMessage, llmPreDecomposeMeta)
|
||||
: false));
|
||||
const sourceIntentHint = deps.toNonEmptyString(carryoverSourceDebug?.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 navigationSessionState = resolveNavigationSessionContextState(
|
||||
addressNavigationState,
|
||||
deps.toNonEmptyString,
|
||||
deps.normalizeOrganizationScopeValue
|
||||
);
|
||||
const navigationFocusObjectHint = navigationSessionState.focusObject;
|
||||
const hasNavigationInventoryItemFocusHint = Boolean(
|
||||
deps.toNonEmptyString(navigationFocusObjectHint?.label) &&
|
||||
deps.toNonEmptyString(navigationFocusObjectHint?.object_type) === "item" &&
|
||||
deps.toNonEmptyString(navigationFocusObjectHint?.objectType) === "item" &&
|
||||
(sourceIntentHint === "inventory_on_hand_as_of_date" ||
|
||||
sourceIntentHint === "inventory_supplier_stock_overlap_as_of_date" ||
|
||||
deps.isInventorySelectedObjectIntent(sourceIntentHint))
|
||||
@@ -643,22 +635,10 @@ export function createAssistantTransitionPolicy(deps) {
|
||||
const previousAnchorContext = resolveAddressDebugAnchorContext(carryoverSourceDebug, deps.toNonEmptyString);
|
||||
let previousAnchorType = previousAnchorContext.anchorType;
|
||||
let previousAnchor = previousAnchorContext.anchorValue;
|
||||
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 navigationDateScope = navigationSessionState.dateScope;
|
||||
const navigationOrganization = navigationSessionState.organization;
|
||||
const navigationFocusObject = navigationSessionState.focusObject;
|
||||
const navigationFocusObjectType = deps.toNonEmptyString(navigationFocusObject?.objectType);
|
||||
const navigationFocusObjectLabel = deps.toNonEmptyString(navigationFocusObject?.label);
|
||||
const hasInventoryItemFocusCarryover =
|
||||
navigationFocusObjectType === "item" &&
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
buildRootScopedCarryoverFilters,
|
||||
hydrateInventoryRootFrameState,
|
||||
readAddressDebugTemporalScope,
|
||||
resolveNavigationSessionContextState,
|
||||
resolveAddressDebugCarryoverFilters,
|
||||
resolveAddressDebugContextFacts,
|
||||
resolveAddressDebugAnchorContext,
|
||||
@@ -111,6 +112,40 @@ describe("assistantContinuityPolicy organization authority", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("resolves navigation session context through one shared helper", () => {
|
||||
const state = resolveNavigationSessionContextState({
|
||||
session_context: {
|
||||
organization_scope: "Org Alt",
|
||||
active_result_set_id: "rs-42",
|
||||
date_scope: {
|
||||
as_of_date: "2020-03-31",
|
||||
period_from: "2020-03-01",
|
||||
period_to: "2020-03-31"
|
||||
},
|
||||
active_focus_object: {
|
||||
object_type: "item",
|
||||
label: "Workstation",
|
||||
provenance_result_set_id: "rs-focus"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
expect(state).toEqual({
|
||||
organization: "Org Alt",
|
||||
activeResultSetId: "rs-42",
|
||||
dateScope: {
|
||||
as_of_date: "2020-03-31",
|
||||
period_from: "2020-03-01",
|
||||
period_to: "2020-03-31"
|
||||
},
|
||||
focusObject: {
|
||||
objectType: "item",
|
||||
label: "Workstation",
|
||||
provenanceResultSetId: "rs-focus"
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("resolves carryover temporal scope and inferred anchor from debug filters when explicit anchor fields are absent", () => {
|
||||
const debug = {
|
||||
extracted_filters: {
|
||||
|
||||
Reference in New Issue
Block a user