АРЧ АП11 - Архитектура после регресса: Архитектура: централизовать anchor и temporal carryover в continuity policy и протянуть их в transition hot path
This commit is contained in:
@@ -5,6 +5,8 @@ exports.readAddressDebugFilters = readAddressDebugFilters;
|
||||
exports.readAddressDebugItem = readAddressDebugItem;
|
||||
exports.readAddressDebugOrganization = readAddressDebugOrganization;
|
||||
exports.readAddressDebugScopedDate = readAddressDebugScopedDate;
|
||||
exports.readAddressDebugTemporalScope = readAddressDebugTemporalScope;
|
||||
exports.resolveAddressDebugAnchorContext = resolveAddressDebugAnchorContext;
|
||||
exports.resolveAddressDebugContextFacts = resolveAddressDebugContextFacts;
|
||||
exports.buildInventoryRootFrameFromAddressDebug = buildInventoryRootFrameFromAddressDebug;
|
||||
exports.isGroundedAddressDebug = isGroundedAddressDebug;
|
||||
@@ -60,6 +62,58 @@ function readAddressDebugScopedDate(debug) {
|
||||
formatIsoDateForReply(rootFrameContext?.as_of_date) ??
|
||||
formatIsoDateForReply(extractedFilters?.period_to));
|
||||
}
|
||||
function readAddressDebugTemporalScope(debug, toNonEmptyString = fallbackToNonEmptyString) {
|
||||
const extractedFilters = readAddressDebugFilters(debug);
|
||||
const rootFrameContext = toRecordObject(debug?.address_root_frame_context);
|
||||
return {
|
||||
asOfDate: toNonEmptyString(extractedFilters?.as_of_date) ?? toNonEmptyString(rootFrameContext?.as_of_date),
|
||||
periodFrom: toNonEmptyString(extractedFilters?.period_from) ?? toNonEmptyString(rootFrameContext?.period_from),
|
||||
periodTo: toNonEmptyString(extractedFilters?.period_to) ?? toNonEmptyString(rootFrameContext?.period_to)
|
||||
};
|
||||
}
|
||||
function resolveAddressDebugAnchorContext(debug, toNonEmptyString = fallbackToNonEmptyString) {
|
||||
const explicitAnchorType = toNonEmptyString(debug?.anchor_type);
|
||||
const explicitAnchorValue = toNonEmptyString(debug?.anchor_value_resolved) ?? toNonEmptyString(debug?.anchor_value_raw);
|
||||
if (explicitAnchorType || explicitAnchorValue) {
|
||||
return {
|
||||
anchorType: explicitAnchorType,
|
||||
anchorValue: explicitAnchorValue
|
||||
};
|
||||
}
|
||||
const extractedFilters = readAddressDebugFilters(debug);
|
||||
const item = toNonEmptyString(extractedFilters?.item);
|
||||
if (item) {
|
||||
return {
|
||||
anchorType: "item",
|
||||
anchorValue: item
|
||||
};
|
||||
}
|
||||
const counterparty = toNonEmptyString(extractedFilters?.counterparty);
|
||||
if (counterparty) {
|
||||
return {
|
||||
anchorType: "counterparty",
|
||||
anchorValue: counterparty
|
||||
};
|
||||
}
|
||||
const account = toNonEmptyString(extractedFilters?.account);
|
||||
if (account) {
|
||||
return {
|
||||
anchorType: "account",
|
||||
anchorValue: account
|
||||
};
|
||||
}
|
||||
const contract = toNonEmptyString(extractedFilters?.contract);
|
||||
if (contract) {
|
||||
return {
|
||||
anchorType: "contract",
|
||||
anchorValue: contract
|
||||
};
|
||||
}
|
||||
return {
|
||||
anchorType: null,
|
||||
anchorValue: null
|
||||
};
|
||||
}
|
||||
function resolveAddressDebugContextFacts(debug, toNonEmptyString = fallbackToNonEmptyString) {
|
||||
return {
|
||||
item: readAddressDebugItem(debug, toNonEmptyString),
|
||||
|
||||
@@ -3,69 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.runAssistantLivingChatRuntime = runAssistantLivingChatRuntime;
|
||||
const assistantMemoryRecapPolicy_1 = require("./assistantMemoryRecapPolicy");
|
||||
const assistantContinuityPolicy_1 = require("./assistantContinuityPolicy");
|
||||
function formatIsoDateForReply(value) {
|
||||
const source = String(value ?? "").trim();
|
||||
const match = source.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
return `${match[3]}.${match[2]}.${match[1]}`;
|
||||
}
|
||||
function findLastGroundedInventoryAddressDebug(items) {
|
||||
if (!Array.isArray(items)) {
|
||||
return null;
|
||||
}
|
||||
for (let index = items.length - 1; index >= 0; index -= 1) {
|
||||
const item = items[index];
|
||||
if (!item || item.role !== "assistant" || !item.debug || typeof item.debug !== "object") {
|
||||
continue;
|
||||
}
|
||||
const debug = item.debug;
|
||||
const answerGroundingCheck = debug.answer_grounding_check && typeof debug.answer_grounding_check === "object"
|
||||
? debug.answer_grounding_check
|
||||
: null;
|
||||
const groundingStatus = String(answerGroundingCheck?.status ?? "");
|
||||
const detectedIntent = String(debug.detected_intent ?? "");
|
||||
const capabilityId = String(debug.capability_id ?? "");
|
||||
const rootFrameContext = debug.address_root_frame_context && typeof debug.address_root_frame_context === "object"
|
||||
? debug.address_root_frame_context
|
||||
: null;
|
||||
const rootIntent = String(rootFrameContext?.root_intent ?? "");
|
||||
const isInventoryContext = detectedIntent === "inventory_on_hand_as_of_date" ||
|
||||
capabilityId === "confirmed_inventory_on_hand_as_of_date" ||
|
||||
rootIntent === "inventory_on_hand_as_of_date";
|
||||
if (groundingStatus === "grounded" && isInventoryContext) {
|
||||
return debug;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function findLastAddressDebugWithItem(items) {
|
||||
if (!Array.isArray(items)) {
|
||||
return null;
|
||||
}
|
||||
for (let index = items.length - 1; index >= 0; index -= 1) {
|
||||
const item = items[index];
|
||||
if (!item || item.role !== "assistant" || !item.debug || typeof item.debug !== "object") {
|
||||
continue;
|
||||
}
|
||||
const debug = item.debug;
|
||||
if (String(debug.execution_lane ?? "") !== "address_query") {
|
||||
continue;
|
||||
}
|
||||
const extractedFilters = debug.extracted_filters && typeof debug.extracted_filters === "object"
|
||||
? debug.extracted_filters
|
||||
: null;
|
||||
const itemLabel = String(extractedFilters?.item ?? "").trim() ||
|
||||
(String(debug.anchor_type ?? "") === "item"
|
||||
? String(debug.anchor_value_resolved ?? debug.anchor_value_raw ?? "").trim()
|
||||
: "");
|
||||
if (itemLabel) {
|
||||
return debug;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function hasPriorAssistantTurn(items) {
|
||||
if (!Array.isArray(items)) {
|
||||
return false;
|
||||
@@ -75,21 +12,6 @@ function hasPriorAssistantTurn(items) {
|
||||
function buildDeterministicSmalltalkLeadReply() {
|
||||
return "\u041f\u0440\u0438\u0432\u0435\u0442! \u0412\u0441\u0451 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e.";
|
||||
}
|
||||
function findLastAddressDebug(items) {
|
||||
if (!Array.isArray(items)) {
|
||||
return null;
|
||||
}
|
||||
for (let index = items.length - 1; index >= 0; index -= 1) {
|
||||
const item = items[index];
|
||||
if (!item || item.role !== "assistant" || !item.debug || typeof item.debug !== "object") {
|
||||
continue;
|
||||
}
|
||||
if (String(item.debug.execution_lane ?? "") === "address_query") {
|
||||
return item.debug;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function buildInventoryHistoryCapabilityFollowupReply(input) {
|
||||
const rootFrameContext = input.addressDebug?.address_root_frame_context && typeof input.addressDebug.address_root_frame_context === "object"
|
||||
? input.addressDebug.address_root_frame_context
|
||||
@@ -100,8 +22,8 @@ function buildInventoryHistoryCapabilityFollowupReply(input) {
|
||||
const organization = input.organization ??
|
||||
input.toNonEmptyString(rootFrameContext?.organization) ??
|
||||
input.toNonEmptyString(extractedFilters?.organization);
|
||||
const lastAsOfDate = formatIsoDateForReply(rootFrameContext?.as_of_date) ??
|
||||
formatIsoDateForReply(extractedFilters?.as_of_date);
|
||||
const lastAsOfDate = (0, assistantContinuityPolicy_1.formatIsoDateForReply)(rootFrameContext?.as_of_date) ??
|
||||
(0, assistantContinuityPolicy_1.formatIsoDateForReply)(extractedFilters?.as_of_date);
|
||||
const organizationPart = organization ? ` по компании «${organization}»` : "";
|
||||
const referenceLine = lastAsOfDate
|
||||
? `Да, могу. Сейчас мы уже смотрели складской срез${organizationPart} на ${lastAsOfDate}.`
|
||||
@@ -132,9 +54,9 @@ function buildAddressMemoryRecapReply(input) {
|
||||
const organization = input.organization ??
|
||||
input.toNonEmptyString(extractedFilters?.organization) ??
|
||||
input.toNonEmptyString(rootFrameContext?.organization);
|
||||
const scopedDate = formatIsoDateForReply(extractedFilters?.as_of_date) ??
|
||||
formatIsoDateForReply(rootFrameContext?.as_of_date) ??
|
||||
formatIsoDateForReply(extractedFilters?.period_to);
|
||||
const scopedDate = (0, assistantContinuityPolicy_1.formatIsoDateForReply)(extractedFilters?.as_of_date) ??
|
||||
(0, assistantContinuityPolicy_1.formatIsoDateForReply)(rootFrameContext?.as_of_date) ??
|
||||
(0, assistantContinuityPolicy_1.formatIsoDateForReply)(extractedFilters?.period_to);
|
||||
if (item) {
|
||||
const datePart = scopedDate ? ` в срезе на ${scopedDate}` : "";
|
||||
const organizationPart = organization ? ` по компании «${organization}»` : "";
|
||||
|
||||
@@ -340,6 +340,7 @@ function createAssistantTransitionPolicy(deps) {
|
||||
mergeKnownOrganizations: deps.mergeKnownOrganizations
|
||||
});
|
||||
const continuitySnapshot = organizationAuthority.continuitySnapshot;
|
||||
const continuityTemporalScope = (0, assistantContinuityPolicy_1.readAddressDebugTemporalScope)(continuitySnapshot.lastGroundedAddressDebug, deps.toNonEmptyString);
|
||||
const organizationClarificationCandidates = Array.isArray(organizationAuthority.organizationClarificationCandidates)
|
||||
? organizationAuthority.organizationClarificationCandidates
|
||||
: [];
|
||||
@@ -522,13 +523,9 @@ function createAssistantTransitionPolicy(deps) {
|
||||
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 previousAnchorContext = (0, assistantContinuityPolicy_1.resolveAddressDebugAnchorContext)(previousAddressDebug, 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
|
||||
@@ -699,8 +696,8 @@ function createAssistantTransitionPolicy(deps) {
|
||||
}
|
||||
if (shouldBackfillPreviousDateScopeFromNavigation &&
|
||||
!deps.toNonEmptyString(previousFilters.as_of_date) &&
|
||||
(0, assistantContinuityPolicy_1.readAddressDebugFilters)(continuitySnapshot.lastGroundedAddressDebug)?.as_of_date) {
|
||||
previousFilters.as_of_date = deps.toNonEmptyString((0, assistantContinuityPolicy_1.readAddressDebugFilters)(continuitySnapshot.lastGroundedAddressDebug)?.as_of_date);
|
||||
continuityTemporalScope.asOfDate) {
|
||||
previousFilters.as_of_date = continuityTemporalScope.asOfDate;
|
||||
}
|
||||
if (shouldBackfillPreviousDateScopeFromNavigation &&
|
||||
!deps.toNonEmptyString(previousFilters.period_from) &&
|
||||
@@ -709,8 +706,8 @@ function createAssistantTransitionPolicy(deps) {
|
||||
}
|
||||
if (shouldBackfillPreviousDateScopeFromNavigation &&
|
||||
!deps.toNonEmptyString(previousFilters.period_from) &&
|
||||
(0, assistantContinuityPolicy_1.readAddressDebugFilters)(continuitySnapshot.lastGroundedAddressDebug)?.period_from) {
|
||||
previousFilters.period_from = deps.toNonEmptyString((0, assistantContinuityPolicy_1.readAddressDebugFilters)(continuitySnapshot.lastGroundedAddressDebug)?.period_from);
|
||||
continuityTemporalScope.periodFrom) {
|
||||
previousFilters.period_from = continuityTemporalScope.periodFrom;
|
||||
}
|
||||
if (shouldBackfillPreviousDateScopeFromNavigation &&
|
||||
!deps.toNonEmptyString(previousFilters.period_to) &&
|
||||
@@ -719,8 +716,8 @@ function createAssistantTransitionPolicy(deps) {
|
||||
}
|
||||
if (shouldBackfillPreviousDateScopeFromNavigation &&
|
||||
!deps.toNonEmptyString(previousFilters.period_to) &&
|
||||
(0, assistantContinuityPolicy_1.readAddressDebugFilters)(continuitySnapshot.lastGroundedAddressDebug)?.period_to) {
|
||||
previousFilters.period_to = deps.toNonEmptyString((0, assistantContinuityPolicy_1.readAddressDebugFilters)(continuitySnapshot.lastGroundedAddressDebug)?.period_to);
|
||||
continuityTemporalScope.periodTo) {
|
||||
previousFilters.period_to = continuityTemporalScope.periodTo;
|
||||
}
|
||||
const rootContextOnlyPivot = Boolean((deps.isInventorySelectedObjectIntent(sourceIntentHint) || currentFrameKind === "inventory_drilldown") &&
|
||||
deps.hasForeignAccountingPivotOverInventoryMessage(userMessage, alternateMessage) &&
|
||||
|
||||
Reference in New Issue
Block a user