ARCH: замкнуть grounded entity retarget на value-flow follow-up

This commit is contained in:
2026-04-22 15:07:20 +03:00
parent 1fd8062dc7
commit acacada0f6
9 changed files with 325 additions and 6 deletions
@@ -727,7 +727,10 @@ export function buildAssistantMcpDiscoveryTurnInput(
(followupSeed.counterparty || followupSeed.discoveryEntity) &&
(followupSeed.pilotScope === "entity_resolution_search_v1" ||
followupSeed.pilotScope === "counterparty_document_evidence_query_documents_v1" ||
followupSeed.pilotScope === "counterparty_movement_evidence_query_movements_v1")
followupSeed.pilotScope === "counterparty_movement_evidence_query_movements_v1" ||
followupSeed.pilotScope === "counterparty_value_flow_query_movements_v1" ||
followupSeed.pilotScope === "counterparty_supplier_payout_query_movements_v1" ||
followupSeed.pilotScope === "counterparty_bidirectional_value_flow_query_movements_v1")
);
const documentEvidenceGroundedMovementFollowupApplicable = Boolean(
followupSeed.pilotScope === "counterparty_document_evidence_query_documents_v1" &&
@@ -2563,6 +2563,12 @@ function hasAddressFollowupContextSignal(userMessage) {
if (ultraShortFollowup && hasAny(/^(?:давай|показывай|показывыай|ещ[её]|also|again|go|ok|okay)(?=$|[\s,.;:!?])/iu)) {
return true;
}
const shortValueFlowRetargetCue = shortFollowup &&
(hasMarker() || hasPointer() || hasAny(/^(?:Р°|a|Рё|i|also|then|now)(?=$|[\s,.;:!?])/iu)) &&
hasAny(/(?:РЅРµССРѕ|сальдо|разниС|полуСРёР»|заплаСРёР»|РїРѕСЃССѓРї|РІСРѕРґСЏС|РёСЃСРѕРґСЏС|РѕР±РѕСЂРѕС|РІССЂСѓСРє|денеР)/iu);
if (shortValueFlowRetargetCue) {
return true;
}
if (hasStandaloneAddressTopicSignal(rawText || repairedText)) {
return false;
}
@@ -321,6 +321,27 @@ export function createAssistantTransitionPolicy(deps) {
return sameDatePhrases.some((phrase) => normalized.includes(phrase));
}
function hasShortValueFlowRetargetCue(text) {
const normalized = normalizeFollowupText(text);
if (!normalized) {
return false;
}
const tokenCount = deps.countTokens(normalized);
if (!Number.isFinite(tokenCount) || tokenCount > 8) {
return false;
}
const hasLeadCue =
deps.hasFollowupMarker(text) ||
deps.hasReferentialPointer(text) ||
/^(?:\u0430|\u0438|also|then|now)(?=$|[\s,.;:!?])/iu.test(normalized);
if (!hasLeadCue) {
return false;
}
return /(?:\u043d\u0435\u0442\u0442\u043e|\u0441\u0430\u043b\u044c\u0434\u043e|\u0440\u0430\u0437\u043d\u0438\u0446|\u043f\u043e\u043b\u0443\u0447|\u0437\u0430\u043f\u043b\u0430\u0442|\u043f\u043e\u0441\u0442\u0443\u043f|\u0432\u0445\u043e\u0434\u044f\u0449|\u0438\u0441\u0445\u043e\u0434\u044f\u0449|\u043e\u0431\u043e\u0440\u043e\u0442|\u0432\u044b\u0440\u0443\u0447\u043a|\u0434\u0435\u043d\u0435\u0436)/iu.test(
normalized
);
}
function shouldKeepPreviousIntentForShortCounterpartyRetarget(userMessage, sourceIntent) {
const normalized = deps.compactWhitespace(
deps.repairAddressMojibake(String(userMessage ?? "")).toLowerCase()
@@ -450,6 +471,15 @@ export function createAssistantTransitionPolicy(deps) {
? deps.isImplicitAddressContinuationByLlm(alternateMessage, llmPreDecomposeMeta)
: false));
const sourceIntentHint = readAddressDebugIntent(carryoverSourceDebug, deps.toNonEmptyString);
const sourceDiscoveryPilotScopeHint = readAssistantMcpDiscoveryPilotScope(
carryoverSourceDebug,
deps.toNonEmptyString
);
const hasValueFlowCarryoverSourceHint =
sourceIntentHint === "customer_revenue_and_payments" ||
sourceDiscoveryPilotScopeHint === "counterparty_value_flow_query_movements_v1" ||
sourceDiscoveryPilotScopeHint === "counterparty_supplier_payout_query_movements_v1" ||
sourceDiscoveryPilotScopeHint === "counterparty_bidirectional_value_flow_query_movements_v1";
const navigationSessionState = resolveNavigationSessionContextState(
addressNavigationState,
deps.toNonEmptyString,
@@ -485,14 +515,22 @@ export function createAssistantTransitionPolicy(deps) {
? deps.resolveDebtRoleSwapFollowupIntent(String(alternateMessage ?? ""), sourceIntentHint)
: null;
const debtRoleSwapIntent = debtRoleSwapPrimary ?? debtRoleSwapAlternate ?? null;
const shortValueFlowRetargetPrimary =
hasValueFlowCarryoverSourceHint && hasShortValueFlowRetargetCue(userMessage);
const shortValueFlowRetargetAlternate =
hasValueFlowCarryoverSourceHint && deps.toNonEmptyString(alternateMessage)
? hasShortValueFlowRetargetCue(String(alternateMessage ?? ""))
: false;
let hasPrimaryFollowupSignal =
deps.hasAddressFollowupContextSignal(userMessage) ||
Boolean(debtRoleSwapPrimary) ||
shortValueFlowRetargetPrimary ||
inventoryShortFollowupPrimary ||
inventoryPurchaseDateVatBridge;
let hasAlternateFollowupSignal = deps.toNonEmptyString(alternateMessage)
? deps.hasAddressFollowupContextSignal(alternateMessage) ||
Boolean(debtRoleSwapAlternate) ||
shortValueFlowRetargetAlternate ||
inventoryShortFollowupAlternate ||
inventoryPurchaseDateVatBridge
: false;
@@ -543,6 +581,8 @@ export function createAssistantTransitionPolicy(deps) {
hasInventoryRootRestatementAlternate ||
inventoryPurchaseDateVatBridge ||
Boolean(debtRoleSwapIntent) ||
shortValueFlowRetargetPrimary ||
shortValueFlowRetargetAlternate ||
deps.hasFollowupMarker(userMessage) ||
deps.hasReferentialPointer(userMessage) ||
(deps.toNonEmptyString(alternateMessage)
@@ -561,6 +601,8 @@ export function createAssistantTransitionPolicy(deps) {
hasInventoryRootRestatementAlternate ||
inventoryPurchaseDateVatBridge ||
Boolean(debtRoleSwapIntent) ||
shortValueFlowRetargetPrimary ||
shortValueFlowRetargetAlternate ||
deps.hasFollowupMarker(userMessage) ||
deps.hasReferentialPointer(userMessage) ||
(deps.toNonEmptyString(alternateMessage)
@@ -588,6 +630,8 @@ export function createAssistantTransitionPolicy(deps) {
!hasInventoryRootTemporalFollowupAlternate &&
!hasInventoryRootRestatementPrimary &&
!hasInventoryRootRestatementAlternate &&
!shortValueFlowRetargetPrimary &&
!shortValueFlowRetargetAlternate &&
!hasImplicitContinuationSignal &&
!hasOrganizationClarificationContinuation &&
!hasIndexReferenceSignal
@@ -601,6 +645,8 @@ export function createAssistantTransitionPolicy(deps) {
!hasInventoryRootTemporalFollowupAlternate &&
!hasInventoryRootRestatementPrimary &&
!hasInventoryRootRestatementAlternate &&
!shortValueFlowRetargetPrimary &&
!shortValueFlowRetargetAlternate &&
!hasImplicitContinuationSignal &&
!hasOrganizationClarificationContinuation &&
!hasIndexReferenceSignal
@@ -611,7 +657,7 @@ export function createAssistantTransitionPolicy(deps) {
return null;
}
const sourceIntent = readAddressDebugIntent(carryoverSourceDebug, deps.toNonEmptyString);
const sourceDiscoveryPilotScope = readAssistantMcpDiscoveryPilotScope(carryoverSourceDebug, deps.toNonEmptyString);
const sourceDiscoveryPilotScope = sourceDiscoveryPilotScopeHint;
const sourceDiscoveryMetadataRouteFamily = readAssistantMcpDiscoveryMetadataRouteFamily(
carryoverSourceDebug,
deps.toNonEmptyString
@@ -730,12 +776,14 @@ export function createAssistantTransitionPolicy(deps) {
hasPrimaryFollowupSignal =
deps.hasAddressFollowupContextSignal(userMessage) ||
Boolean(debtRoleSwapPrimary) ||
shortValueFlowRetargetPrimary ||
inventoryShortFollowupPrimary ||
inventoryPurchaseDateVatBridge ||
hasInventoryRootTemporalFollowupPrimary;
hasAlternateFollowupSignal = deps.toNonEmptyString(alternateMessage)
? deps.hasAddressFollowupContextSignal(alternateMessage) ||
Boolean(debtRoleSwapAlternate) ||
shortValueFlowRetargetAlternate ||
inventoryShortFollowupAlternate ||
inventoryPurchaseDateVatBridge ||
hasInventoryRootTemporalFollowupAlternate
@@ -751,6 +799,8 @@ export function createAssistantTransitionPolicy(deps) {
hasInventoryRootTemporalFollowupAlternate ||
inventoryPurchaseDateVatBridge ||
Boolean(debtRoleSwapIntent) ||
shortValueFlowRetargetPrimary ||
shortValueFlowRetargetAlternate ||
deps.hasFollowupMarker(userMessage) ||
deps.hasReferentialPointer(userMessage) ||
(deps.toNonEmptyString(alternateMessage)