NODEDC_1C/llm_normalizer/backend/dist/services/assistantLivingModePolicy.js

361 lines
27 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createAssistantLivingModePolicy = createAssistantLivingModePolicy;
function createAssistantLivingModePolicy(deps) {
const { featureAssistantLivingChatRouterV1, compactWhitespace, repairAddressMojibake, toNonEmptyString, normalizeOrganizationScopeValue, hasReferentialPointer, hasSmallTalkSignal, hasAssistantCapabilityQuestionSignal, hasOperationalAdminActionRequestSignal, resolveProviderExecutionState } = deps;
function hasStrongDataIntentSignal(text) {
const lower = String(text ?? "").toLowerCase();
return /(база|док|документ|проводк|контрагент|договор|контракт|счет|сч[её]т|остат|сальдо|хвост|платеж|плат[её]ж|операц|поставщик|клиент|заказчик|дебитор|кредитор|оборот|баланс|период|месяц|год|инн|аванс|предоплат|отгруз|задолж|долг|склад|товар|номенклат|материал|mcp|bank|counterparty|contract|document|ledger|posting|account|organization|company|advance|prepay|shipment|receivab|payab|warehouse|inventory|stock|item|организац|компан|контор|фирм)/i.test(lower);
}
function hasDataRetrievalRequestSignal(text) {
const lower = compactWhitespace(repairAddressMojibake(String(text ?? "")).toLowerCase());
if (!lower) {
return false;
}
const hasBroadInterrogative = /(?:\u0433\u0434\u0435|\u0432\s+\u043a\u0430\u043a\u0438\u0445|\u043f\u043e\s+\u043a\u0430\u043a\u0438\u043c|\u043f\u043e\s+\u043a\u043e\u043c\u0443|\u043a\u0430\u043a\u0438\u0435|\u043a\u0430\u043a\u043e\u0439|\u043a\u0442\u043e|\u0441\u043a\u043e\u043b\u044c\u043a\u043e|where|which|who|how\s+many)/iu.test(lower);
const hasBroadBusinessObject = /(?:\u0430\u0432\u0430\u043d\u0441|\u043f\u0440\u0435\u0434\u043e\u043f\u043b\u0430\u0442|\u043e\u0442\u0433\u0440\u0443\u0437|\u0437\u0430\u0434\u043e\u043b\u0436|\u0434\u043e\u043b\u0433|\u0441\u0430\u043b\u044c\u0434\u043e|\u043e\u043f\u043b\u0430\u0442|\u043f\u043b\u0430\u0442(?:\u0435|\u0451)\u0436|\u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442|\u0434\u043e\u0433\u043e\u0432\u043e\u0440|\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442|\u0441\u0447(?:\u0435|\u0451)\u0442|\u043e\u0431\u043e\u0440\u043e\u0442|\u043f\u0435\u0440\u0438\u043e\u0434|\u043c\u0435\u0441\u044f\u0446|\u0433\u043e\u0434|\u0441\u043a\u043b\u0430\u0434|\u0442\u043e\u0432\u0430\u0440|\u043d\u043e\u043c\u0435\u043d\u043a\u043b\u0430\u0442|\u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b|advance|prepay|shipment|receivab|payab|counterparty|contract|document|account|balance|turnover|warehouse|inventory|stock|item)/iu.test(lower);
if (hasBroadInterrogative && hasBroadBusinessObject) {
return true;
}
const hasRussianRetrievalAction = /(?:^|\s)(?:\u043f\u043e\u043a\u0430\u0436\u0438|\u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c|\u043d\u0430\u0439\u0434\u0438|\u0432\u044b\u0432\u0435\u0434\u0438|\u0434\u0430\u0439|\u0440\u0430\u0441\u043a\u0440\u043e\u0439|\u0441\u043f\u0438\u0441\u043e\u043a|\u043f\u0440\u043e\u0432\u0435\u0440\u044c|\u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c)(?:$|[\s,.!?;:])/iu.test(lower);
const hasRussianRetrievalObject = /(?:\u0434\u043e\u0433\u043e\u0432\u043e\u0440|\u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442|\u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442|\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442|\u0441\u0447(?:\u0435|\u0451)\u0442|\u043e\u0441\u0442\u0430\u0442|\u0441\u0430\u043b\u044c\u0434\u043e|\u043e\u0431\u043e\u0440\u043e\u0442|\u043f\u043b\u0430\u0442(?:\u0435|\u0451)\u0436|\u043e\u043f\u0435\u0440\u0430\u0446|\u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a|\u043a\u043b\u0438\u0435\u043d\u0442|\u0433\u043e\u0434|\u043f\u0435\u0440\u0438\u043e\u0434|\u043c\u0435\u0441\u044f\u0446|\u0430\u0432\u0430\u043d\u0441|\u043f\u0440\u0435\u0434\u043e\u043f\u043b\u0430\u0442|\u043e\u0442\u0433\u0440\u0443\u0437|\u0437\u0430\u0434\u043e\u043b\u0436|\u0434\u043e\u043b\u0433|\u0441\u043a\u043b\u0430\u0434|\u0442\u043e\u0432\u0430\u0440|\u043d\u043e\u043c\u0435\u043d\u043a\u043b\u0430\u0442|\u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b)/iu.test(lower);
if (hasRussianRetrievalAction && hasRussianRetrievalObject) {
return true;
}
const hasExplicitRetrievalAction = /(?:\bпокажи\b|\bпоказать\b|\bвыведи\b|\bнайди\b|\bсписок\b|\bдай\b|\bраскрой\b|\bshow\b|\blist\b|\bfind\b|\bcount\b)/i.test(lower);
const hasInterrogativeRetrievalAction = /(?:\bсколько\b|\bкакой\b|\bкакая\b|\bкакое\b|\bкакую\b|\bкакие\b|\bкто\b|\bгде\b|\bпо\s+каким\b|\bпо\s+кому\b|\bу\s+кого\b|\bwhich\b|\bwho\b|\bwhere\b)/i.test(lower);
if (!hasExplicitRetrievalAction && !hasInterrogativeRetrievalAction) {
return false;
}
const hasRetrievalObject = /(1с|база|док|документ|контрагент|договор|контракт|счет|сч[её]т|остат|сальдо|хвост|платеж|плат[её]ж|операц|поставщик|клиент|заказчик|дебитор|кредитор|период|месяц|год|инн|аванс|предоплат|отгруз|задолж|долг|склад|товар|номенклат|материал|bank|counterparty|contract|document|account|balance|ledger|posting|advance|prepay|shipment|receivab|payab|warehouse|inventory|stock|item|организац|компан|контор|фирм|возраст|дата\s+регистрац|регистрац|основан)/i.test(lower);
if (!hasRetrievalObject) {
return false;
}
if (hasExplicitRetrievalAction) {
return true;
}
const hasMetaCapabilityShape = /(?:мож(?:ем|ешь|ете|но)|уме(?:ешь|ете)|доступ|подключ|чья|как\s+называ(?:ет|ется)|работ(?:ать|аем|аешь|аете)|в\s+тебе|у\s+тебя)/i.test(lower);
return !hasMetaCapabilityShape;
}
function hasOrganizationFactLookupSignal(text) {
const repaired = repairAddressMojibake(String(text ?? ""));
const normalized = compactWhitespace(repaired.toLowerCase()).replace(/ё/g, "е");
if (!normalized) {
return false;
}
const hasFactCue = /(?:возраст|сколько\s+лет|дата\s+регистрац|когда\s+(?:зарегистр|создан|основан)|год\s+регистрац|год\s+основан|с\s+какого\s+года|when\s+was\s+(?:it\s+)?(?:registered|founded|created))/i.test(normalized);
if (!hasFactCue) {
return false;
}
return /(?:организац|компан|контор|фирм|ооо|ао|зао|ип|альтернатив|лайсвуд|райм|organization|company)/i.test(normalized);
}
function findLastAssistantLivingChatDebug(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") {
continue;
}
if (item.debug && typeof item.debug === "object") {
return item.debug;
}
}
return null;
}
function hasMetaAnswerFollowupSignal(userMessage) {
const rawText = compactWhitespace(String(userMessage ?? "").toLowerCase());
const repairedText = compactWhitespace(repairAddressMojibake(String(userMessage ?? "")).toLowerCase());
const samples = [rawText, repairedText]
.filter((item) => item.length > 0)
.map((item) => item.replace(/ё/g, "е"));
if (samples.length === 0) {
return false;
}
const hasReflectionCue = samples.some((sample) => sample.includes("дума") ||
sample.includes("скаж") ||
sample.includes("мнение") ||
sample.includes("как тебе") ||
sample.includes("норм") ||
sample.includes("стран") ||
sample.includes("логич") ||
sample.includes("смуща") ||
sample.includes("выгляд"));
const hasTopicPointerCue = samples.some((sample) => sample.includes("на эту тему") ||
sample.includes("по этому поводу") ||
sample.includes("об этом") ||
(sample.includes("это") && hasReferentialPointer(sample)));
const hasEvaluationCue = samples.some((sample) => /\b(?:много|мало|нормально|хорошо|плохо|критично|перебор|слабо)\b/iu.test(sample));
if (!((hasReflectionCue || hasEvaluationCue) &&
(hasTopicPointerCue || (hasEvaluationCue && samples.some((sample) => /^(?:это|ну это)\b/iu.test(sample)))))) {
return false;
}
return !samples.some((sample) => hasAssistantDataScopeMetaQuestionSignal(sample) ||
shouldHandleAsAssistantCapabilityMetaQuery(sample) ||
hasDataRetrievalRequestSignal(sample) ||
hasStrongDataIntentSignal(sample));
}
function hasConversationMemoryRecallFollowupSignal(userMessage) {
const rawText = compactWhitespace(String(userMessage ?? "").toLowerCase());
const repairedText = compactWhitespace(repairAddressMojibake(String(userMessage ?? "")).toLowerCase());
const samples = [rawText, repairedText]
.filter((item) => item.length > 0)
.map((item) => item.replace(/ё/g, "е"));
if (samples.length === 0) {
return false;
}
const hasMemoryCue = samples.some((sample) => /(?:помни(?:шь|те|м)?|remember|recall)/iu.test(sample));
const hasDiscussionCue = samples.some((sample) => /(?:обсуждал[аи]?|говорил[аи]?|смотрел[аи]?|разбирал[аи]?|спрашивал[аи]?)/iu.test(sample));
const hasExplicitRecapPrompt = samples.some((sample) => /(?:что\s+мы\s+.*(?:обсуждали|выяснили)|что\s+уже\s+выяснили|напомни\s+что\s+мы|what\s+we\s+already\s+(?:discussed|figured\s+out))/iu.test(sample));
if (!(hasExplicitRecapPrompt || (hasMemoryCue && hasDiscussionCue))) {
return false;
}
if (hasExplicitRecapPrompt) {
return !samples.some((sample) => hasAssistantDataScopeMetaQuestionSignal(sample) ||
shouldHandleAsAssistantCapabilityMetaQuery(sample));
}
return !samples.some((sample) => hasAssistantDataScopeMetaQuestionSignal(sample) ||
shouldHandleAsAssistantCapabilityMetaQuery(sample) ||
hasDataRetrievalRequestSignal(sample) ||
hasStrongDataIntentSignal(sample));
}
function hasHistoricalCapabilityFollowupSignal(text) {
const repaired = repairAddressMojibake(String(text ?? ""));
const normalized = compactWhitespace(repaired.toLowerCase()).replace(/ё/g, "е");
if (!normalized) {
return false;
}
const hasHistoryCue = /(?:историческ|история|архив|прошл(?:ый|ые|ую|ых)?|раньше|ретро|старые\s+данные)/iu.test(normalized);
if (!hasHistoryCue) {
return false;
}
return /(?:мож(?:ешь|ете|но)|уме(?:ешь|ете)|показ|вывед|дай|раскрой)/iu.test(normalized);
}
function hasOrganizationFactFollowupSignal(userMessage, items) {
const repaired = repairAddressMojibake(String(userMessage ?? ""));
const normalized = compactWhitespace(repaired.toLowerCase()).replace(/ё/g, "е");
if (!normalized) {
return false;
}
if (hasOrganizationFactLookupSignal(normalized)) {
return false;
}
const hasFollowupCue = /(?:^|\s)(?:давай|го|погнали|ок(?:ей)?|хорошо|принято|подтверждаю|запрашивай|запроси|проверь|продолжай|ну\s+давай|да\s+давай)(?=$|[\s,.!?;:])/iu.test(normalized);
if (!hasFollowupCue) {
return false;
}
const lastDebug = findLastAssistantLivingChatDebug(items);
const lastSource = toNonEmptyString(lastDebug?.living_chat_response_source);
const lastGuardReason = toNonEmptyString(lastDebug?.living_chat_grounding_guard_reason);
const inOrganizationFactBoundary = lastSource === "deterministic_organization_fact_boundary" ||
lastSource === "deterministic_organization_fact_boundary_followup" ||
lastGuardReason === "organization_fact_without_live_source_blocked";
return inOrganizationFactBoundary;
}
function shouldEmitOrganizationSelectionReply(userMessage, selectedOrganization) {
const selected = normalizeOrganizationScopeValue(selectedOrganization);
if (!selected) {
return false;
}
const repaired = repairAddressMojibake(String(userMessage ?? ""));
const normalized = compactWhitespace(repaired.toLowerCase()).replace(/ё/g, "е");
if (!normalized) {
return false;
}
if (hasOrganizationFactLookupSignal(normalized) || hasDataRetrievalRequestSignal(normalized) || hasStrongDataIntentSignal(normalized)) {
return false;
}
const hasAnalyticalCue = /(?:какой|какая|какие|когда|сколько|кто|почему|зачем|возраст|дата|регистрац|ндс|налог|контракт|договор|документ|операц|оборот|сумм|остат|сальдо|founded|registered|created)/i.test(normalized);
if (hasAnalyticalCue) {
return false;
}
const hasSelectionCue = /(?:давай|го|погнали|ок(?:ей)?|хорошо|отлично|берем|выберем|выбираем|переключ(?:им|аем|ай)|фиксир|работаем|обсудим|тогда)\b/i.test(normalized);
if (hasSelectionCue) {
return true;
}
const hasAffectiveReactionCue = /(?:^|[\s,.;:!?()\-])(?:ну|мда|ох|ах|офигеть|офигенно|ахуеть|охуеть|пиздец|пизда|нихуя|хуево|хуёво|ебать|ебан|бля|блять|fuck|shit|damn)(?=$|[\s,.;:!?()\-])/iu.test(normalized) ||
normalized.includes("\u0430\u0445\u0443") ||
normalized.includes("\u043e\u0445\u0443") ||
normalized.includes("\u043f\u0438\u0437\u0434") ||
normalized.includes("\u0431\u043b\u044f");
if (hasAffectiveReactionCue) {
return false;
}
return normalized.length <= 36 && !/[?]/.test(String(userMessage ?? ""));
}
function hasAssistantDataScopeMetaQuestionSignal(text) {
const repaired = repairAddressMojibake(String(text ?? ""));
const lower = compactWhitespace(repaired.toLowerCase()).replace(/ё/g, "е");
const normalized = lower.replace(/\b1\s*[cс]\b/giu, "1с");
if (!normalized) {
return false;
}
const hasDirectSlangScopeLead = /(?:по\s+каким\s+(?:контор(?:ам|ы|а)?|кантор(?:ам|ы|а)?|компан(?:иям|ии|ию|ия)|организац(?:иям|ии|ию|ия))\s+мож(?:ем|но)\s+(?:общат|работ)|база\s+какой\s+(?:контор|компан|организац|фирм)|какая\s+база\s+(?:подключ|подруб|актив))/iu.test(normalized);
if (hasDirectSlangScopeLead) {
return true;
}
const hasSlangScopeQuestion = /(?:\u043f\u043e\s+\u043a\u0430\u043a\u0438\u043c\s+(?:\u043a\u043e\u043d\u0442\u043e\u0440(?:\u0430\u043c|\u044b|\u0430)?|\u043a\u043e\u043c\u043f\u0430\u043d(?:\u0438\u044f\u043c|\u0438\u0438|\u0438\u044e|\u0438\u044f)|\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446(?:\u0438\u044f\u043c|\u0438\u0438|\u0438\u044e|\u0438\u044f)|\u0444\u0438\u0440\u043c(?:\u0430\u043c|\u0435|\u0443|\u0430)).*(?:\u043c\u043e\u0436(?:\u0435\u043c|\u043d\u043e)|\u0440\u0430\u0431\u043e\u0442|\u043e\u0431\u0449\u0430\u0442|\u043f\u043e\u0434\u0440\u0443\u0431|\u043f\u043e\u0434\u043a\u043b\u044e\u0447)|(?:\u0431\u0430\u0437\u0430\s+\u043a\u0430\u043a\u043e\u0439\s+(?:\u043a\u043e\u043d\u0442\u043e\u0440|\u043a\u043e\u043c\u043f\u0430\u043d|\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446|\u0444\u0438\u0440\u043c))|(?:\u043a\u0430\u043a\u0430\u044f\s+\u0431\u0430\u0437\u0430\s+(?:\u043f\u043e\u0434\u043a\u043b\u044e\u0447|\u0430\u043a\u0442\u0438\u0432)))/iu.test(normalized);
if (hasSlangScopeQuestion) {
return true;
}
const hasBaseOrTenantObject = /(?:баз(?:а|е|у|ы)?|тенант|tenant|контур)/i.test(normalized);
const hasCompanyObject = /(?:компан(?:ия|ии|ию|ией)|компин(?:ия|ии|ию|ией)?|компини(?:я|и|ю|ей)?|компани[яеию]|организац(?:ия|ии|ию|ией)|контор(?:а|ы|у|ой)?|фирм(?:а|ы|у|ой)?)/i.test(normalized);
const hasConnectionCue = /(?:подключен(?:а|о|ы)?|подруб|воткнут|активн(?:ый|ая)\s+канал|mcp-?канал|канал)/i.test(normalized);
const hasNamingCue = /(?:как\s+называ(?:ет|ется)|что\s+за\s+(?:контор|компан|организац|фирм))/i.test(normalized);
const hasWorkabilityCue = /(?:мож(?:ем|ешь|ете|но)\s+работ|работ(?:ать|аем|аешь|аете))/i.test(normalized);
const hasScopeObject = hasBaseOrTenantObject || hasCompanyObject || hasConnectionCue;
if (!hasScopeObject) {
return false;
}
const hasMetaPerspective = /(?:ты|тебе|твой|у\s+тебя|в\s+тебе|мы|нам|наш(?:а|е|и|у|ей)?|сейчас|щас)/i.test(normalized);
const hasScopedInterrogativePair = /(?:^|\s)(?:по\s+какой|с\s+какой|какая|какой|какие)\s+(?:баз|компан|компин|компини|компани|организац|контор|фирм|тенант|контур)/i.test(normalized);
const hasScopeQuestion = /(?:чья|чье|чьи|доступн|подключен|подруб|воткнут|какая\s+баз|какой\s+баз)/i.test(normalized) ||
hasNamingCue ||
hasWorkabilityCue ||
hasScopedInterrogativePair;
const hasInterrogativeScopeLead = /(?:^|\s)(?:по\s+какой|с\s+какой|чья|чье|чьи|which|who|what)/i.test(normalized);
const isQuestionLike = /[?]/.test(String(text ?? "")) || hasInterrogativeScopeLead || hasScopedInterrogativePair;
const hasExplicitScopeContext = hasBaseOrTenantObject || hasConnectionCue || hasWorkabilityCue || hasNamingCue;
const hasRetrievalSignal = hasDataRetrievalRequestSignal(normalized);
const hasContractAnalyticsCue = /(?:договор|контракт|contract).*(?:топ|сам(?:ый|ая|ое|ые)|крупн|жирн|оборот|бюджет|сумм|стоим|value|turnover|all\s+time|всю\s+истори|за\s+вс[её]\s+время)/iu.test(normalized);
if (hasContractAnalyticsCue) {
return false;
}
if (hasRetrievalSignal && !hasExplicitScopeContext) {
return false;
}
const hasEligibleScopeObject = hasBaseOrTenantObject || (hasCompanyObject && (hasConnectionCue || hasWorkabilityCue || hasNamingCue || hasMetaPerspective));
return hasEligibleScopeObject && hasScopeQuestion && (hasMetaPerspective || isQuestionLike || hasExplicitScopeContext);
}
function shouldHandleAsAssistantCapabilityMetaQuery(text) {
const raw = String(text ?? "");
const repaired = repairAddressMojibake(raw);
const hasScopeMetaSignal = hasAssistantDataScopeMetaQuestionSignal(raw) || hasAssistantDataScopeMetaQuestionSignal(repaired);
if (hasScopeMetaSignal) {
return true;
}
const hasExplicitDeltaCapabilityMetaSignal = /(?:мож(?:ешь|ете)|уме(?:ешь|ете)).*(?:считать|рассчитывать|посчитать).*(?:дельт|delta|маржинальн|margin|рентабельн)/iu.test(raw) ||
/(?:мож(?:ешь|ете)|уме(?:ешь|ете)).*(?:считать|рассчитывать|посчитать).*(?:дельт|delta|маржинальн|margin|рентабельн)/iu.test(repaired);
if (hasExplicitDeltaCapabilityMetaSignal) {
return true;
}
const hasCapabilitySignal = hasAssistantCapabilityQuestionSignal(raw) ||
hasAssistantCapabilityQuestionSignal(repaired) ||
hasOperationalAdminActionRequestSignal(raw) ||
hasOperationalAdminActionRequestSignal(repaired);
const hasRetrievalSignal = hasDataRetrievalRequestSignal(raw) || hasDataRetrievalRequestSignal(repaired);
return hasCapabilitySignal && !hasRetrievalSignal;
}
function hasLivingChatSignal(text) {
const rawLower = compactWhitespace(String(text ?? "").toLowerCase());
const repairedLower = compactWhitespace(repairAddressMojibake(String(text ?? "")).toLowerCase());
const variants = [rawLower, repairedLower].filter((value, index, items) => value.length > 0 && items.indexOf(value) === index);
if (variants.length === 0) {
return false;
}
const hasDirectionalReply = variants.some((value) => /^(?:\u0430\s+)?(?:\u0442\u0443\u0442|\u0437\u0434\u0435\u0441\u044c|\u0442\u0430\u043c|\u0441\u044e\u0434\u0430|\u0442\u0443\u0434\u0430)[\s!?.,:;\-]*$/iu.test(value));
if (hasDirectionalReply) {
return true;
}
const hasShortGreeting = variants.some((value) => /^(?:\u0430\u0433\u0430|\u0443\u0433\u0443|\u043e\u043a|\u043e\u043a\u0435\u0439|\u044f\u0441\u043d\u043e|\u043f\u043e\u043d\u044f\u043b(?:\u0430)?|\u043f\u0440\u0438\u043d\u044f\u0442\u043e|\u0441\u043f\u0430\u0441\u0438\u0431\u043e|\u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044e|\u0441\u0443\u043f\u0435\u0440|\u043a\u043b\u0430\u0441\u0441|\u043d\u043e\u0440\u043c|\u0433\u043e|\u0434\u0430\u0432\u0430\u0439|\u043f\u043e\u0433\u043d\u0430\u043b\u0438|\u043f\u0440\u0438\u0432\u0435\u0442(?:\u0438\u043a)?|\u0445\u0430\u0439|\u0439\u043e|yo|\u0447[её]\s+\u0442\u0430\u043c|\u0447[её]\s+\u043a\u0430\u043a|hello|hi|thanks?)$/iu.test(value));
if (hasShortGreeting) {
return true;
}
const hasGreetingWithFollowup = variants.some((value) => /(?:^|[\s,.!?;:()\-])(?:\u043f\u0440\u0438\u0432\u0435\u0442\p{L}*|\u0445\u0430\u0439|\u0439\u043e|hello|hi|yo)(?=$|[\s,.!?;:()\-]).*(?:^|[\s,.!?;:()\-])(?:\u043a\u0430\u043a|\u0434\u0435\u043b\u0430|\u0442\u0430\u043c|\u0447[её])(?=$|[\s,.!?;:()\-])/iu.test(value));
if (hasGreetingWithFollowup) {
return true;
}
const hasColloquialFollowup = variants.some((value) => /(?:^|[\s,.!?;:()\-])(?:\u0447[её]\s+\u043a\u0430\u043a|\u0447[её]\s+\u0442\u0430\u043c|\u043a\u0430\u043a\s+\u0442\u0430\u043c(?:\s+\u0434\u0435\u043b\u0430)?)(?=$|[\s,.!?;:()\-])/iu.test(value));
if (hasColloquialFollowup) {
return true;
}
const hasOpenSmalltalkPrompt = variants.some((value) => /(?:\u043a\u0430\u043a\s+\u0434\u0435\u043b\u0430|\u043a\u0430\u043a\s+\u0442\u044b|\u0447\u0442\u043e\s+\u043d\u043e\u0432\u043e\u0433\u043e|\u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0438\s+\u043e\s+\u0441\u0435\u0431\u0435|\u0447\u0435\u043c\s+\u043c\u043e\u0436\u0435\u0448\u044c\s+\u043f\u043e\u043c\u043e\u0447\u044c|\u0434\u0430\u0432\u0430\u0439\s+\u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c|\u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c|\u043e\u0431\u0441\u0443\u0434\u0438\u043c|\u043f\u043e\u0441\u043e\u0432\u0435\u0442\u0443\u0439|\u0447\u0442\u043e\s+\u0434\u0443\u043c\u0430\u0435\u0448\u044c)/iu.test(value));
if (hasOpenSmalltalkPrompt) {
return true;
}
return variants.some((value) => hasSmallTalkSignal(value));
}
function resolveLivingAssistantModeDecision(input) {
const userMessage = String(input?.userMessage ?? "");
if (input?.addressLaneTriggered) {
return {
mode: "address_data",
reason: "address_lane_triggered"
};
}
if (!featureAssistantLivingChatRouterV1) {
return {
mode: "deep_analysis",
reason: "living_chat_router_disabled"
};
}
const providerExecution = resolveProviderExecutionState({
llmProvider: input?.llmProvider,
useMock: input?.useMock
});
if (providerExecution.living_mode_forced_deep) {
return {
mode: "deep_analysis",
reason: providerExecution.living_mode_forced_reason ?? "mock_mode_keeps_deep_pipeline"
};
}
if (hasAssistantDataScopeMetaQuestionSignal(userMessage)) {
return {
mode: "chat",
reason: "assistant_data_scope_query_detected"
};
}
if (shouldHandleAsAssistantCapabilityMetaQuery(userMessage)) {
return {
mode: "chat",
reason: "assistant_capability_query_detected"
};
}
if (hasOrganizationFactLookupSignal(userMessage) || hasOrganizationFactFollowupSignal(userMessage)) {
return {
mode: "chat",
reason: "organization_fact_lookup_signal_detected"
};
}
if (hasStrongDataIntentSignal(userMessage)) {
return {
mode: "deep_analysis",
reason: "strong_data_signal_detected"
};
}
if (hasLivingChatSignal(userMessage)) {
return {
mode: "chat",
reason: "living_chat_signal_detected"
};
}
const predecomposeMode = toNonEmptyString(input?.predecomposeMode);
const predecomposeConfidence = toNonEmptyString(input?.predecomposeModeConfidence);
if (predecomposeMode === "unsupported" && (predecomposeConfidence === "low" || predecomposeConfidence === "medium")) {
return {
mode: "deep_analysis",
reason: "predecompose_unsupported_mode_fallback_to_deep"
};
}
return {
mode: "deep_analysis",
reason: "default_deep_pipeline"
};
}
return {
hasStrongDataIntentSignal,
hasDataRetrievalRequestSignal,
hasOrganizationFactLookupSignal,
hasMetaAnswerFollowupSignal,
hasConversationMemoryRecallFollowupSignal,
hasHistoricalCapabilityFollowupSignal,
hasOrganizationFactFollowupSignal,
shouldEmitOrganizationSelectionReply,
hasAssistantDataScopeMetaQuestionSignal,
shouldHandleAsAssistantCapabilityMetaQuery,
hasLivingChatSignal,
resolveLivingAssistantModeDecision
};
}