ARCH: усилить semantic integrity и добавить human AGENT сценарии

This commit is contained in:
2026-04-23 19:10:28 +03:00
parent 62e2b3323f
commit 65d15c156b
29 changed files with 1966 additions and 93 deletions
@@ -5,6 +5,7 @@ exports.cloneAddressNavigationState = cloneAddressNavigationState;
exports.normalizeAddressNavigationState = normalizeAddressNavigationState;
exports.evolveAddressNavigationStateWithAssistantItem = evolveAddressNavigationStateWithAssistantItem;
const nanoid_1 = require("nanoid");
const assistantContinuityPolicy_1 = require("./assistantContinuityPolicy");
const addressNavigation_1 = require("../types/addressNavigation");
const MAX_RESULT_SETS = 40;
const MAX_NAVIGATION_EVENTS = 120;
@@ -242,24 +243,32 @@ function resolveNavigationAction(debug, hasFocusObject) {
}
return hasFocusObject ? "drilldown" : "open";
}
function buildFocusObjectFromDebug(debug, resultSetId, createdAt) {
const extractedFilters = toObject(debug.extracted_filters) ?? {};
const rawValue = toNonEmptyString(debug.anchor_value_resolved) ??
toNonEmptyString(debug.anchor_value_raw) ??
toNonEmptyString(extractedFilters.item);
if (!rawValue) {
return null;
}
const objectType = toAddressFocusObjectType(debug.anchor_type);
const canonicalType = objectType === "unknown" ? inferDisplayEntityType(toAddressIntent(debug.detected_intent)) : objectType;
function buildFocusObject(objectType, label, resultSetId, createdAt) {
return {
object_type: canonicalType,
object_id: `${canonicalType}:${rawValue}`.toLowerCase(),
label: rawValue,
object_type: objectType,
object_id: `${objectType}:${label}`.toLowerCase(),
label,
provenance_result_set_id: resultSetId,
selected_at: createdAt
};
}
function buildFocusObjectFromDebug(debug, resultSetId, createdAt) {
const extractedFilters = toObject(debug.extracted_filters) ?? {};
const objectType = toAddressFocusObjectType(debug.anchor_type);
const canonicalType = objectType === "unknown" ? inferDisplayEntityType(toAddressIntent(debug.detected_intent)) : objectType;
if (canonicalType === "item") {
const item = (0, assistantContinuityPolicy_1.readAddressDebugItem)(debug, toNonEmptyString);
return item ? buildFocusObject(canonicalType, item, resultSetId, createdAt) : null;
}
if (canonicalType === "counterparty" && debug.mcp_discovery_response_applied === true) {
const counterparty = (0, assistantContinuityPolicy_1.readAddressDebugCounterparty)(debug, toNonEmptyString);
return counterparty ? buildFocusObject(canonicalType, counterparty, resultSetId, createdAt) : null;
}
const rawValue = toNonEmptyString(debug.anchor_value_resolved) ??
toNonEmptyString(debug.anchor_value_raw) ??
toNonEmptyString(extractedFilters.item);
return rawValue ? buildFocusObject(canonicalType, rawValue, resultSetId, createdAt) : null;
}
function capResultSets(resultSets) {
if (resultSets.length <= MAX_RESULT_SETS) {
return resultSets;
@@ -0,0 +1,73 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.repairAddressMojibakeText = repairAddressMojibakeText;
exports.normalizeRussianComparableText = normalizeRussianComparableText;
const iconv_lite_1 = __importDefault(require("iconv-lite"));
function compactWhitespace(value) {
return value.replace(/\s+/g, " ").trim();
}
function textMojibakeScore(value) {
const source = String(value ?? "");
const cyrillic = (source.match(/[\u0400-\u04ff]/g) ?? []).length;
const latin = (source.match(/[A-Za-z]/g) ?? []).length;
const replacement = (source.match(/[�]/g) ?? []).length;
const pairMarkers = (source.match(/(?:Р.|С.|Ð.|Ñ.)/g) ?? []).length;
const doubleEncodedMarkers = (source.match(/(?:Р“[Р-џ]|Р’[Р-џ]|Ã.|Â.)/gu) ?? []).length;
return cyrillic + latin - replacement * 3 - pairMarkers * 2 - doubleEncodedMarkers * 2;
}
function looksLikeAddressMojibake(value) {
const source = String(value ?? "");
if (!source.trim()) {
return false;
}
if (/[�]/.test(source)) {
return true;
}
if ((source.match(/(?:Р.|С.|Ð.|Ñ.)/g) ?? []).length >= 2) {
return true;
}
if ((source.match(/(?:Р“[Р-џ]|Р’[Р-џ]|Ã.|Â.)/gu) ?? []).length >= 2) {
return true;
}
return false;
}
function repairAddressMojibakeText(value) {
const source = String(value ?? "");
if (!looksLikeAddressMojibake(source)) {
return source;
}
let candidate = source;
for (let pass = 0; pass < 3; pass += 1) {
let improved = false;
try {
const fromWin1251 = iconv_lite_1.default.encode(candidate, "win1251").toString("utf8");
if (textMojibakeScore(fromWin1251) > textMojibakeScore(candidate)) {
candidate = fromWin1251;
improved = true;
}
}
catch {
// Ignore decode failures and keep the current candidate.
}
try {
const fromLatin1 = Buffer.from(candidate, "latin1").toString("utf8");
if (textMojibakeScore(fromLatin1) > textMojibakeScore(candidate)) {
candidate = fromLatin1;
improved = true;
}
}
catch {
// Ignore decode failures and keep the current candidate.
}
if (!improved) {
break;
}
}
return candidate;
}
function normalizeRussianComparableText(value) {
return compactWhitespace(repairAddressMojibakeText(String(value ?? "")).toLowerCase()).replace(/ё/g, "е");
}
@@ -77,12 +77,17 @@ function shouldPreferRawFollowupMessage(userMessage, addressInputMessage, carryo
const previousIntent = toNonEmptyString(followupContext?.previous_intent);
const rootIntent = toNonEmptyString(followupContext?.root_intent);
const previousAnchorType = toNonEmptyString(followupContext?.previous_anchor_type);
const hasReferentialDocumentExclusionFollowupCue = /(?:\u043a\u0440\u043e\u043c\u0435|\u043f\u043e\u043c\u0438\u043c\u043e)\s+(?:\u044d\u0442\u043e\u0433\u043e|\u044d\u0442\u043e\u0439|\u044d\u0442\u043e\u0442|\u044d\u0442\u0443|\u044d\u0442\u0438\u0445)(?:\s+(?:\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430|\u0434\u043e\u0433\u043e\u0432\u043e\u0440\u0430|\u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\u0430))?/iu.test(rawMessage);
const hasInventoryItemCarryover = previousAnchorType === "item" && isInventorySelectedObjectOrRootIntent(previousIntent);
const hasInventoryFrameCarryover = isInventorySelectedObjectOrRootIntent(previousIntent) ||
isInventorySelectedObjectOrRootIntent(rootIntent);
const hasDocumentCarryover = previousIntent === "list_documents_by_counterparty" || previousIntent === "list_documents_by_contract";
if (mode === "unsupported" && intent === "unknown") {
return true;
}
if (hasDocumentCarryover && hasReferentialDocumentExclusionFollowupCue) {
return true;
}
if (hasSameDateFollowupSignal(rawMessage) && hasExplicitCurrentDateSignal(canonicalMessage)) {
return true;
}
@@ -51,6 +51,7 @@ exports.resolveAssistantContinuitySnapshot = resolveAssistantContinuitySnapshot;
exports.resolveAssistantOrganizationAuthority = resolveAssistantOrganizationAuthority;
exports.resolveOrganizationClarificationContinuation = resolveOrganizationClarificationContinuation;
const assistantOrganizationMatcher_1 = require("./assistantOrganizationMatcher");
const addressTextRepair_1 = require("./addressTextRepair");
function fallbackToNonEmptyString(value) {
if (value === null || value === undefined) {
return null;
@@ -365,14 +366,45 @@ function readAddressDebugItem(debug, toNonEmptyString = fallbackToNonEmptyString
? toNonEmptyString(debug?.anchor_value_resolved) ?? toNonEmptyString(debug?.anchor_value_raw)
: null));
}
function readAddressDebugCounterparty(debug, toNonEmptyString = fallbackToNonEmptyString) {
const extractedFilters = readAddressDebugFilters(debug);
if (toNonEmptyString(extractedFilters?.counterparty)) {
return toNonEmptyString(extractedFilters?.counterparty);
function isReferentialCounterpartyPlaceholder(value) {
if (!value) {
return false;
}
if (String(debug?.anchor_type ?? "") === "counterparty") {
return toNonEmptyString(debug?.anchor_value_resolved) ?? toNonEmptyString(debug?.anchor_value_raw);
return new Set([
"он",
"она",
"оно",
"они",
"ему",
"ней",
"нему",
"ним",
"ними",
"его",
"ее",
"их",
"этому",
"этой",
"этом",
"этим",
"эта",
"этот",
"эти"
]).has((0, addressTextRepair_1.normalizeRussianComparableText)(value));
}
function normalizeCounterpartyCandidate(value, toNonEmptyString) {
const text = toNonEmptyString(value);
if (!text || isReferentialCounterpartyPlaceholder(text)) {
return null;
}
return text;
}
function sameCounterpartyCandidate(left, right) {
return Boolean(left &&
right &&
(0, addressTextRepair_1.normalizeRussianComparableText)(left) === (0, addressTextRepair_1.normalizeRussianComparableText)(right));
}
function readGroundedDiscoveryCounterparty(debug, toNonEmptyString = fallbackToNonEmptyString) {
const discoveryPilotScope = readAssistantMcpDiscoveryPilotScope(debug, toNonEmptyString);
const suppressDiscoveryEntityCarryover = discoveryPilotScope === "metadata_inspection_v1" ||
readAssistantMcpDiscoveryLoopSubjectResolutionOptional(debug);
@@ -381,12 +413,27 @@ function readAddressDebugCounterparty(debug, toNonEmptyString = fallbackToNonEmp
}
const discoveryEntities = collectAssistantMcpDiscoveryEntityCandidates(debug, toNonEmptyString);
for (const entity of discoveryEntities) {
const text = toNonEmptyString(entity);
if (text) {
return text;
const normalized = normalizeCounterpartyCandidate(entity, toNonEmptyString);
if (normalized) {
return normalized;
}
}
return null;
return normalizeCounterpartyCandidate(readAssistantMcpDiscoveryLoopMetadataScopeHint(debug, toNonEmptyString), toNonEmptyString);
}
function readAddressDebugCounterparty(debug, toNonEmptyString = fallbackToNonEmptyString) {
const extractedFilters = readAddressDebugFilters(debug);
const extractedCounterparty = normalizeCounterpartyCandidate(extractedFilters?.counterparty, toNonEmptyString);
const anchorCounterparty = String(debug?.anchor_type ?? "") === "counterparty"
? normalizeCounterpartyCandidate(toNonEmptyString(debug?.anchor_value_resolved) ?? toNonEmptyString(debug?.anchor_value_raw), toNonEmptyString)
: null;
const groundedDiscoveryCounterparty = readGroundedDiscoveryCounterparty(debug, toNonEmptyString);
if (hasGroundedDiscoveryBusinessAnswer(debug, toNonEmptyString) && groundedDiscoveryCounterparty) {
if (!extractedCounterparty || !sameCounterpartyCandidate(extractedCounterparty, groundedDiscoveryCounterparty)) {
return groundedDiscoveryCounterparty;
}
return extractedCounterparty;
}
return extractedCounterparty ?? anchorCounterparty ?? groundedDiscoveryCounterparty;
}
function readAddressDebugIntent(debug, toNonEmptyString = fallbackToNonEmptyString) {
const detectedIntent = toNonEmptyString(debug?.detected_intent);
@@ -431,8 +478,16 @@ function readAddressDebugTemporalScope(debug, toNonEmptyString = fallbackToNonEm
}
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) {
const explicitAnchorValueRaw = toNonEmptyString(debug?.anchor_value_resolved) ?? toNonEmptyString(debug?.anchor_value_raw);
const explicitAnchorValue = explicitAnchorType === "counterparty"
? normalizeCounterpartyCandidate(explicitAnchorValueRaw, toNonEmptyString)
: explicitAnchorValueRaw;
const groundedDiscoveryCounterparty = readGroundedDiscoveryCounterparty(debug, toNonEmptyString);
const shouldPreferDiscoveryCounterparty = explicitAnchorType === "counterparty" &&
Boolean(groundedDiscoveryCounterparty &&
hasGroundedDiscoveryBusinessAnswer(debug, toNonEmptyString) &&
(!explicitAnchorValue || !sameCounterpartyCandidate(explicitAnchorValue, groundedDiscoveryCounterparty)));
if ((explicitAnchorType || explicitAnchorValue) && !shouldPreferDiscoveryCounterparty) {
return {
anchorType: explicitAnchorType,
anchorValue: explicitAnchorValue
@@ -446,8 +501,11 @@ function resolveAddressDebugAnchorContext(debug, toNonEmptyString = fallbackToNo
anchorValue: item
};
}
const counterparty = toNonEmptyString(extractedFilters?.counterparty);
if (counterparty) {
const counterparty = normalizeCounterpartyCandidate(extractedFilters?.counterparty, toNonEmptyString);
if (counterparty &&
!(groundedDiscoveryCounterparty &&
hasGroundedDiscoveryBusinessAnswer(debug, toNonEmptyString) &&
!sameCounterpartyCandidate(counterparty, groundedDiscoveryCounterparty))) {
return {
anchorType: "counterparty",
anchorValue: counterparty
@@ -512,7 +570,9 @@ function resolveAddressDebugCarryoverFilters(debug, toNonEmptyString = fallbackT
Boolean(discoveryDateScope.asOfDate || discoveryDateScope.periodFrom || discoveryDateScope.periodTo);
const counterparty = readAddressDebugCounterparty(debug, toNonEmptyString);
const organization = readAddressDebugOrganization(debug, toNonEmptyString);
if (counterparty && !toNonEmptyString(nextFilters.counterparty)) {
const preferGroundedDiscoveryCounterparty = hasGroundedDiscoveryBusinessAnswer(debug, toNonEmptyString) && Boolean(counterparty);
const existingCounterparty = normalizeCounterpartyCandidate(nextFilters.counterparty, toNonEmptyString);
if (counterparty && (preferGroundedDiscoveryCounterparty || !existingCounterparty)) {
nextFilters.counterparty = counterparty;
}
if (organization && !toNonEmptyString(nextFilters.organization)) {
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
exports.ASSISTANT_MCP_DISCOVERY_TURN_INPUT_SCHEMA_VERSION = void 0;
exports.buildAssistantMcpDiscoveryTurnInput = buildAssistantMcpDiscoveryTurnInput;
const assistantMcpDiscoveryDataNeedGraph_1 = require("./assistantMcpDiscoveryDataNeedGraph");
const addressTextRepair_1 = require("./addressTextRepair");
exports.ASSISTANT_MCP_DISCOVERY_TURN_INPUT_SCHEMA_VERSION = "assistant_mcp_discovery_turn_input_v1";
function toRecordObject(value) {
if (!value || typeof value !== "object" || Array.isArray(value)) {
@@ -38,7 +39,32 @@ function pushUnique(target, value) {
}
}
function isReferentialEntityPlaceholder(value) {
return /^(?:\u043d\u0435\u043c\u0443|\u043d\u0435\u0439|\u043d\u0438\u043c|\u043d\u0438\u043c\u0438|\u0435\u0433\u043e|\u0435\u0435|\u0435\u0451|\u0438\u0445|\u044d\u0442\u043e\u043c\u0443|\u044d\u0442\u043e\u0439|\u044d\u0442\u0438\u043c|\u044d\u0442\u0438\u043c\u0438|\u044d\u0442\u043e\u043c)$/iu.test(value.trim());
return new Set([
"он",
"она",
"оно",
"они",
"ему",
"ней",
"нему",
"ним",
"ними",
"его",
"ее",
"их",
"этому",
"этой",
"этим",
"этими",
"этом"
]).has((0, addressTextRepair_1.normalizeRussianComparableText)(value));
}
function normalizeFollowupCounterpartyCandidate(value) {
const text = candidateValue(value);
if (!text || isReferentialEntityPlaceholder(text)) {
return null;
}
return text;
}
function pushScopedEntityCandidate(target, value, groundedFollowupEntity) {
const text = candidateValue(value);
@@ -347,14 +373,22 @@ function collectFollowupDiscoverySeed(followupContext) {
const entityResolutionAmbiguityCandidates = collectEntityCandidates(followupContext?.previous_discovery_entity_ambiguity_candidates);
const ambiguityBlocksImplicitGrounding = effectivePilotScope === "entity_resolution_search_v1" && entityResolutionStatus === "ambiguous";
const metadataPilotCarriesScopeOnly = effectivePilotScope === "metadata_inspection_v1" || loopSubjectResolutionOptional;
const normalizedDiscoveryEntities = discoveryEntities
.map((entity) => normalizeFollowupCounterpartyCandidate(entity))
.filter((entity) => Boolean(entity));
const groundedDiscoveryCounterparty = ambiguityBlocksImplicitGrounding || metadataPilotCarriesScopeOnly
? null
: normalizedDiscoveryEntities[0] ?? normalizeFollowupCounterpartyCandidate(loopMetadataScopeHint);
const metadataScopeHint = loopMetadataScopeHint ??
(loopSubjectResolutionOptional ? discoveryEntities[0] ?? null : null);
const counterparty = toNonEmptyString(previousFilters?.counterparty) ??
toNonEmptyString(rootFilters?.counterparty) ??
(toNonEmptyString(followupContext?.previous_anchor_type) === "counterparty"
? toNonEmptyString(followupContext?.previous_anchor_value)
: null) ??
(ambiguityBlocksImplicitGrounding || metadataPilotCarriesScopeOnly ? null : discoveryEntities[0] ?? null);
(loopSubjectResolutionOptional ? normalizedDiscoveryEntities[0] ?? null : null);
const previousFiltersCounterparty = normalizeFollowupCounterpartyCandidate(previousFilters?.counterparty);
const rootFiltersCounterparty = normalizeFollowupCounterpartyCandidate(rootFilters?.counterparty);
const previousAnchorCounterparty = toNonEmptyString(followupContext?.previous_anchor_type) === "counterparty"
? normalizeFollowupCounterpartyCandidate(followupContext?.previous_anchor_value)
: null;
const counterparty = groundedDiscoveryCounterparty
? groundedDiscoveryCounterparty
: previousFiltersCounterparty ?? rootFiltersCounterparty ?? previousAnchorCounterparty;
const organization = toNonEmptyString(previousFilters?.organization) ??
toNonEmptyString(rootFilters?.organization) ??
(toNonEmptyString(followupContext?.previous_anchor_type) === "organization"
@@ -372,7 +406,7 @@ function collectFollowupDiscoverySeed(followupContext) {
loopPendingAxes,
loopProvidedAxes,
counterparty,
discoveryEntity: ambiguityBlocksImplicitGrounding || loopSubjectResolutionOptional ? null : discoveryEntities[0] ?? null,
discoveryEntity: ambiguityBlocksImplicitGrounding || loopSubjectResolutionOptional ? null : normalizedDiscoveryEntities[0] ?? null,
entityResolutionStatus,
entityResolutionAmbiguityCandidates,
rankingNeed: toNonEmptyString(followupContext?.previous_discovery_ranking_need),
@@ -472,6 +506,9 @@ function hasMetadataSignal(text) {
return (/(?:\u043e\u0431\u044a\u0435\u043a\u0442(?:\u044b|\u0430|\u043e\u0432)?|\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u044b|\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u044b|\u0441\u043f\u0440\u0430\u0432\u043e\u0447\u043d\u0438\u043a\u0438|\u043f\u043e\u043b(?:\u0435|\u044f)|objects?|registers?|documents?|catalogs?|fields?)/iu.test(text) &&
/(?:\u0435\u0441\u0442\u044c|\u043a\u0430\u043a\u0438\u0435|\u0434\u043e\u0441\u0442\u0443\u043f\u043d|\u0432\s+1\u0441|1\u0441|available|exist|which)/iu.test(text));
}
function hasReferentialDocumentExclusionFollowupSignal(text) {
return /(?:\u043a\u0440\u043e\u043c\u0435|\u043f\u043e\u043c\u0438\u043c\u043e)\s+(?:\u044d\u0442\u043e\u0433\u043e|\u044d\u0442\u043e\u0439|\u044d\u0442\u043e\u0442|\u044d\u0442\u0443|\u044d\u0442\u0438\u0445)(?:\s+(?:\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430|\u0434\u043e\u0433\u043e\u0432\u043e\u0440\u0430|\u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\u0430))?/iu.test(text);
}
function hasMetadataObjectHint(text) {
return /(?:\u043e\u0431\u044a\u0435\u043a\u0442(?:\u044b|\u0430|\u043e\u0432)?|\u0440\u0435\u0433\u0438\u0441\u0442\u0440(?:\u044b)?|\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442(?:\u044b)?|\u0441\u043f\u0440\u0430\u0432\u043e\u0447\u043d\u0438\u043a(?:\u0438)?|\u043f\u043e\u043b(?:\u0435|\u044f)|objects?|registers?|documents?|catalogs?|fields?)/iu.test(text);
}
@@ -732,14 +769,20 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
const reasonCodes = [];
const rawUserText = toNonEmptyString(input.userMessage);
const rawEffectiveText = toNonEmptyString(input.effectiveMessage);
const rawSignalSourceText = `${rawUserText ?? ""} ${rawEffectiveText ?? ""}`.trim();
const rawEntitySourceText = rawUserText ?? rawEffectiveText ?? rawSignalSourceText;
const repairedUserText = rawUserText ? (0, addressTextRepair_1.repairAddressMojibakeText)(rawUserText) : null;
const repairedEffectiveText = rawEffectiveText ? (0, addressTextRepair_1.repairAddressMojibakeText)(rawEffectiveText) : null;
const rawSignalSourceText = `${repairedUserText ?? rawUserText ?? ""} ${repairedEffectiveText ?? rawEffectiveText ?? ""}`.trim();
const rawEntitySourceText = repairedUserText ?? rawUserText ?? repairedEffectiveText ?? rawEffectiveText ?? rawSignalSourceText;
const rawText = compactLower(rawSignalSourceText);
const rawReferentialDocumentExclusionSignal = hasReferentialDocumentExclusionFollowupSignal(repairedUserText ?? rawUserText ?? "");
const rawLifecycleSignal = hasLifecycleSignal(rawText);
const rawBidirectionalValueFlowSignal = !rawLifecycleSignal && hasBidirectionalValueFlowSignal(rawText);
const rawValueFlowSignal = !rawLifecycleSignal &&
(hasValueFlowSignal(rawText) || hasValueRankingSignal(rawText) || rawBidirectionalValueFlowSignal);
const rawMetadataSignal = !rawLifecycleSignal && !rawValueFlowSignal && hasMetadataSignal(rawText);
const rawMetadataSignal = !rawLifecycleSignal &&
!rawValueFlowSignal &&
!rawReferentialDocumentExclusionSignal &&
hasMetadataSignal(rawText);
const rawEntityResolutionSignal = !rawLifecycleSignal && !rawValueFlowSignal && !rawMetadataSignal && hasEntityResolutionSignal(rawText);
const rawPayoutSignal = rawValueFlowSignal && !rawBidirectionalValueFlowSignal && hasPayoutSignal(rawText);
const monthlyAggregationSignal = hasMonthlyAggregationSignal(rawText);
@@ -495,12 +495,35 @@ function createAssistantRoutePolicy(deps) {
!effectiveAddressFollowupSignal &&
resolvedModeDetection.mode === "unsupported" &&
resolvedIntentResolution.intent === "unknown");
const groundedValueFlowFollowupContextDetected = Boolean(followupContext &&
[
"counterparty_value_flow_query_movements_v1",
"counterparty_supplier_payout_query_movements_v1",
"counterparty_bidirectional_value_flow_query_movements_v1"
].includes(String(toNonEmptyString(followupContext?.previous_discovery_pilot_scope) ?? "")) &&
!dangerOrCoercionSignal &&
(toNonEmptyString(assistantTurnMeaning?.asked_domain_family) === "counterparty_value" ||
[
"turnover",
"payout",
"net_value_flow"
].includes(String(toNonEmptyString(assistantTurnMeaning?.asked_action_family) ?? "")) ||
/(?:нетто|сальдо|сколько\s+мы\s+(?:получили|заплатили)|incoming|outgoing)/iu.test(analyticsSample)));
const baseToolGatePreservesAddressLane = Boolean(baseToolGate?.runAddressLane &&
["address_intent_resolver_detected", "address_mode_classifier_detected", "address_signal_detected", "llm_canonical_data_signal_detected"].includes(String(baseToolGate?.reason ?? "")));
[
"address_intent_resolver_detected",
"address_mode_classifier_detected",
"address_signal_detected",
"llm_canonical_data_signal_detected"
].includes(String(baseToolGate?.reason ?? ""))) ||
Boolean(baseToolGate?.runAddressLane &&
String(baseToolGate?.reason ?? "") === "followup_context_detected" &&
groundedValueFlowFollowupContextDetected);
const nonDomainQueryIndexed = Boolean(!llmFirstAddressCandidate &&
deterministicNonDomainGuard &&
(llmFirstUnsupportedCandidate || llmContractMode === null) &&
!baseToolGatePreservesAddressLane &&
!groundedValueFlowFollowupContextDetected &&
!protectedInventoryShortFollowup &&
!organizationClarificationContinuationDetected);
const lastAddressAssistantDebug = sessionItems
@@ -664,9 +687,11 @@ function createAssistantRoutePolicy(deps) {
const unsupportedCurrentTurnMeaningBoundary = Boolean(assistantTurnMeaning?.unsupported_but_understood_family &&
assistantTurnMeaning?.stale_replay_forbidden === true &&
!turnMeaningIntentCandidate &&
!aggregateBusinessAnalyticsSignal &&
!dataScopeMetaQuery &&
!capabilityMetaQuery &&
!dangerOrCoercionSignal &&
!groundedValueFlowFollowupContextDetected &&
!organizationClarificationContinuationDetected);
if (unsupportedCurrentTurnMeaningBoundary) {
return {