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

486 lines
35 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";
// @ts-nocheck
Object.defineProperty(exports, "__esModule", { value: true });
exports.createAssistantTurnMeaningPolicy = createAssistantTurnMeaningPolicy;
const SUPPORTED_ADDRESS_INTENTS = new Set([
"period_coverage_profile",
"document_type_and_account_section_profile",
"counterparty_population_and_roles",
"counterparty_activity_lifecycle",
"receivables_confirmed_as_of_date",
"payables_confirmed_as_of_date",
"list_documents_by_counterparty",
"bank_operations_by_counterparty",
"list_contracts_by_counterparty",
"customer_revenue_and_payments",
"supplier_payouts_profile",
"open_contracts_confirmed_as_of_date",
"list_open_contracts",
"open_items_by_counterparty_or_contract",
"list_payables_counterparties",
"list_receivables_counterparties",
"inventory_on_hand_as_of_date",
"inventory_purchase_provenance_for_item",
"inventory_purchase_documents_for_item",
"inventory_supplier_stock_overlap_as_of_date",
"inventory_sale_trace_for_item",
"inventory_margin_ranking_for_nomenclature",
"inventory_profitability_for_item",
"inventory_purchase_to_sale_chain",
"inventory_aging_by_purchase_date",
"contract_usage_overview",
"contract_usage_and_value",
"vat_liability_confirmed_for_tax_period",
"vat_payable_confirmed_as_of_date",
"vat_payable_forecast"
]);
function fallbackCompactWhitespace(value) {
return String(value ?? "").replace(/\s+/g, " ").trim();
}
function normalizeTurnText(value, deps) {
const compactWhitespace = typeof deps?.compactWhitespace === "function" ? deps.compactWhitespace : fallbackCompactWhitespace;
const repaired = typeof deps?.repairAddressMojibake === "function"
? deps.repairAddressMojibake(String(value ?? ""))
: String(value ?? "");
return compactWhitespace(repaired.toLowerCase())
.replace(/\u0451/gu, "\u0435")
.replace(/(^|[^\p{L}0-9_])\u043d\u0430\u043c\u0441(?=$|[^\p{L}0-9_])/giu, "$1\u043d\u0430\u043c")
.replace(/(^|[^\p{L}0-9_])\u043a\u0430\u043a\u0438\u0435\u043a(?=$|[^\p{L}0-9_])/giu, "$1\u043a\u0430\u043a\u0438\u0435");
}
function toNonEmptyString(value, deps) {
if (typeof deps?.toNonEmptyString === "function") {
return deps.toNonEmptyString(value);
}
if (value === null || value === undefined) {
return null;
}
const text = String(value).trim();
return text.length > 0 ? text : null;
}
function detectSupportedIntent(text, deps) {
const resolved = typeof deps?.resolveAddressIntent === "function" ? deps.resolveAddressIntent(text) : null;
const resolverIntent = toNonEmptyString(resolved?.intent, deps);
if (resolverIntent && resolverIntent !== "unknown" && SUPPORTED_ADDRESS_INTENTS.has(resolverIntent)) {
return {
intent: resolverIntent,
confidence: toNonEmptyString(resolved?.confidence, deps) ?? "medium",
reason: "address_intent_resolver_current_turn_signal"
};
}
if (/(?:\u043a\u0442\u043e\s+\u043d\u0430\u043c\s+\u0434\u043e\u043b\u0436|\u043d\u0430\u043c\s+\u043a\u0442\u043e\s+\u0434\u043e\u043b\u0436|\u0434\u0435\u0431\u0438\u0442\u043e\u0440|\u0434\u0435\u0431\u0438\u0442\u043e\u0440\u0441\u043a|\breceivables?\b)/iu.test(text)) {
return {
intent: "receivables_confirmed_as_of_date",
confidence: "high",
reason: "receivables_current_turn_meaning_signal"
};
}
if (/(?:\u043a\u043e\u043c\u0443\s+\u043c\u044b\s+\u0434\u043e\u043b\u0436|\u043c\u044b\s+\u043a\u043e\u043c\u0443\s+\u0434\u043e\u043b\u0436|\u043c\u044b\s+\u0434\u043e\u043b\u0436\u043d|\u043a\u0440\u0435\u0434\u0438\u0442\u043e\u0440|\bpayables?\b)/iu.test(text)) {
return {
intent: "payables_confirmed_as_of_date",
confidence: "high",
reason: "payables_current_turn_meaning_signal"
};
}
if (/(?:\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442|\u0434\u043e\u043a\u0438|docs?|documents?)/iu.test(text) && /(?:\u043f\u043e|by)\s+[\p{L}0-9._-]{2,}/iu.test(text)) {
return {
intent: "list_documents_by_counterparty",
confidence: "medium",
reason: "counterparty_documents_current_turn_signal"
};
}
if (/(?:\u043e\u0441\u0442\u0430\u0442|\u0441\u043a\u043b\u0430\u0434|inventory|stock)/iu.test(text)) {
return {
intent: "inventory_on_hand_as_of_date",
confidence: "medium",
reason: "inventory_snapshot_current_turn_signal"
};
}
return null;
}
function detectCounterpartyTurnoverFamily(text) {
const hasTurnoverCue = /(?:\u043e\u0431\u043e\u0440\u043e\u0442|\u0432\u044b\u0440\u0443\u0447\u043a|\u0434\u043e\u0445\u043e\u0434|turnover|revenue)/iu.test(text);
if (!hasTurnoverCue) {
return null;
}
const explicitEntityMatch = text.match(/(?:\u043f\u043e|by|for)?\s*([\p{L}0-9._-]{2,})\s*$/iu);
const rawEntity = explicitEntityMatch?.[1] ?? null;
const ignored = new Set([
"\u043e\u0431\u043e\u0440\u043e\u0442",
"\u0432\u044b\u0440\u0443\u0447\u043a\u0430",
"\u0434\u043e\u0445\u043e\u0434",
"\u0431\u044b\u043b",
"\u0431\u044b\u043b\u0430",
"\u0432\u0440\u0435\u043c\u044f",
"\u0432\u0440\u0435\u043c\u0435\u043d\u0438",
"\u0433\u043e\u0434",
"\u0433\u043e\u0434\u0430",
"\u043f\u0435\u0440\u0438\u043e\u0434",
"\u043f\u0435\u0440\u0438\u043e\u0434\u0430",
"\u043c\u0435\u0441\u044f\u0446",
"\u043c\u0435\u0441\u044f\u0446\u0430",
"\u043a\u0432\u0430\u0440\u0442\u0430\u043b",
"\u043a\u0432\u0430\u0440\u0442\u0430\u043b\u0430",
"turnover",
"revenue",
"time",
"year",
"period",
"month",
"quarter"
]);
const entity = rawEntity && !ignored.has(rawEntity) ? rawEntity : null;
return {
family: "counterparty_value_or_turnover",
entity
};
}
function hasCompactOrganizationCashflowDisplaySignal(text) {
const normalized = String(text ?? "");
if (!normalized) {
return false;
}
const hasCompactCue = /(?:\u043a\u043e\u0440\u043e\u0442\u043a\w*|\u043e\u0434\u043d\u043e\u0439\s+\u0441\u0442\u0440\u043e\u043a\p{L}*|\u0442\u043e\u043b\u044c\u043a\u043e\s+\u0438\u0442\u043e\u0433\p{L}*|\u043d\u0435\s+\u043e\u0431\u0437\u043e\u0440|\u043f\u0440\u043e\u0441\u0442\u043e\s+\u0434\u0435\u043d\p{L}*|\u0431\u0435\u0437\s+\u0442\u043e\u043f(?:\u043e\u0432|\u0430)?\b|\u0431\u0435\u0437\s+\u0441\u043f\u0438\u0441(?:\u043a\p{L}*)?|\u0431\u0435\u0437\s+\u0434\u0435\u0442\u0430\u043b\p{L}*|\u0431\u0435\u0437\s+\u0440\u0430\u0437\u0431\u0438\u0432\p{L}*|\u0431\u0435\u0437\s+\u0440\u0430\u0437\u0440\u0435\u0437\p{L}*|\u0431\u0435\u0437\s+\u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\p{L}*)/iu.test(normalized);
if (!hasCompactCue) {
return false;
}
const hasMoneyCue = /(?:\u0434\u0435\u043d\p{L}*|\u0434\u0435\u043d\u0435\u0436\p{L}*|\u043f\u0440\u0438\u0448\p{L}*|\u0443\u0448\p{L}*|\u043f\u043e\u043b\u0443\u0447\p{L}*|\u0437\u0430\u043f\u043b\u0430\u0442\p{L}*|\u0441\u043f\u0438\u0441\u0430\p{L}*|\u043d\u0435\u0442\u0442\u043e|cash|money|incoming|outgoing|net)/iu.test(normalized);
const hasOrganizationEarningsCue = /(?:\u0434\u0430\u0439|\u043f\u043e\u043a\u0430\u0436\p{L}*|\u0438\u0442\u043e\u0433\p{L}*|\u0441\u043a\u043e\u043b\u044c\u043a\u043e|\u0441\u043a\u043e\u043a\w*|\u0437\u0430\u0440\u0430\u0431\u043e\u0442\p{L}*|\u043f\u0440\u0438\u0448\p{L}*|\u0443\u0448\p{L}*|\u043f\u043e\u043b\u0443\u0447\p{L}*|\u0437\u0430\u043f\u043b\u0430\u0442\p{L}*|\u0434\u0435\u043d\u0435\u0436\p{L}*\s+\u043d\u0435\u0442\u0442\u043e|how\s+much|show|give|earned|received|paid)/iu.test(normalized);
const hasExplicitExclusionCue = /(?:\u0438\u0441\u043a\u043b\u044e\u0447\p{L}*|\u0443\u0431\u0435\u0440\p{L}*|\u043a\u0440\u043e\u043c\u0435|exclude|excluding|without)[\s\S]{0,80}(?:\u043a\u0440\u0443\u043f\u043d\p{L}*|\u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\p{L}*|\u043a\u043b\u0438\u0435\u043d\u0442\p{L}*|\u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a\p{L}*|\u043e\u043f\u0435\u0440\u0430\u0446\p{L}*|counterpart|customer|supplier|operation)/iu.test(normalized);
const hasSpecificCounterpartyScope = detectScopedCounterpartyEntity(normalized) !== null;
return hasMoneyCue && hasOrganizationEarningsCue && !hasExplicitExclusionCue && !hasSpecificCounterpartyScope;
}
function detectScopedCounterpartyEntity(text) {
const patterns = [
/(?:^|[\s,.;:!?])(?:\u043f\u043e|\u0443|\u0434\u043b\u044f|by|for)\s+(.+?)(?=$|[,.;:!?]|\s+(?:\u0437\u0430|\u043d\u0430|\u0432|\u0432\u043e|\u043a|\u043f\u043e|\u0441\u043a\u043e\u043b\u044c\u043a\u043e|\u0441\u043a\u043e\u043a|\u043a\u0430\u043a|\u043a\u0430\u043a\u043e\u0435|\u043a\u0430\u043a\u043e\u0439|\u043a\u0430\u043a\u0430\u044f|\u043a\u0430\u043a\u0438\u0435|\u043f\u043e\u043b\u0443\u0447\p{L}*|\u0437\u0430\u043f\u043b\u0430\u0442\p{L}*|\u043d\u0435\u0442\u0442\u043e|\u0441\u0430\u043b\u044c\u0434\u043e|\u0434\u0435\u043d\u0435\u0433|\u0434\u0435\u043d\u0435\u0436\p{L}*|\u043f\u043b\u0430\u0442[\u0435\u0451]\u0436\p{L}*|\u0438\u0441\u0445\u043e\u0434\p{L}*|\u0432\u0445\u043e\u0434\p{L}*)(?=$|[\s,.;:!?]))/iu,
/(?:^|[\s,.;:!?])(?:\u043f\u043e|\u0443|\u0434\u043b\u044f|by|for)\s+([\p{L}\d._-]{2,})(?=$|[\s,.;:!?])/iu
];
const ignored = new Set([
"\u0433\u043e\u0434",
"\u0433\u043e\u0434\u0430",
"\u043f\u0435\u0440\u0438\u043e\u0434",
"\u043f\u0435\u0440\u0438\u043e\u0434\u0430",
"\u043c\u0435\u0441\u044f\u0446",
"\u043c\u0435\u0441\u044f\u0446\u0430",
"\u043a\u0432\u0430\u0440\u0442\u0430\u043b",
"\u043a\u0432\u0430\u0440\u0442\u0430\u043b\u0430",
"\u0434\u0435\u043d\u044c\u0433\u0438",
"\u043d\u0435\u0442\u0442\u043e",
"\u0441\u0430\u043b\u044c\u0434\u043e",
"year",
"period",
"month",
"quarter",
"net"
]);
for (const pattern of patterns) {
const rawEntity = text.match(pattern)?.[1]?.trim() ?? "";
if (!rawEntity) {
continue;
}
const entity = rawEntity.replace(/^["'«»]+|["'«»]+$/gu, "").trim();
if (entity.length >= 2 && !ignored.has(entity)) {
return entity;
}
}
return null;
}
function detectCounterpartyBidirectionalValueFlowFamily(text) {
const hasNetCue = /(?:\u043d\u0435\u0442\u0442\u043e|\u0441\u0430\u043b\u044c\u0434\u043e|net\s+(?:flow|cash|payment)|cash\s+net)/iu.test(text);
const hasIncomingCue = /(?:\u043f\u043e\u043b\u0443\u0447\p{L}*|\u0432\u0445\u043e\u0434\p{L}*|\u043f\u043e\u0441\u0442\u0443\u043f\p{L}*|received|incoming)/iu.test(text);
const hasOutgoingCue = /(?:\u0437\u0430\u043f\u043b\u0430\u0442\p{L}*|\u0438\u0441\u0445\u043e\u0434\p{L}*|\u0441\u043f\u0438\u0441\u0430\u043d\p{L}*|paid|outgoing|payment)/iu.test(text);
if (!(hasNetCue || (hasIncomingCue && hasOutgoingCue))) {
return null;
}
const entity = detectScopedCounterpartyEntity(text);
if (!entity) {
return null;
}
return {
family: "counterparty_bidirectional_value_flow_or_netting",
entity
};
}
function hasExplicitCounterpartyValueObject(text) {
return /(?:\u043a\u043b\u0438\u0435\u043d\u0442|\u043f\u043e\u043a\u0443\u043f\u0430\u0442\u0435\u043b|\u0437\u0430\u043a\u0430\u0437\u0447\u0438\u043a|\u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442|\u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a|\u0434\u043e\u0433\u043e\u0432\u043e\u0440|\u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442|\u0442\u043e\u0432\u0430\u0440|\u043d\u043e\u043c\u0435\u043d\u043a\u043b\u0430\u0442\u0443\u0440|\u0441\u0434\u0435\u043b\u043a|customer|client|counterparty|supplier|vendor|contract|item|product|deal)/iu.test(text);
}
function hasSelectedObjectInventoryExactSignal(text) {
const normalized = String(text ?? "");
if (!normalized) {
return false;
}
const hasSelectedObjectCue = /(?:\u043f\u043e\s+\u0432\u044b\u0431\u0440\u0430\u043d\u043d(?:\u043e\u043c\u0443|\u043e\u0439)\s+(?:\u043e\u0431\u044a\u0435\u043a\u0442\u0443|\u043f\u043e\u0437\u0438\u0446\u0438\u0438)|selected\s+object|\u043f\u043e\s+\u044d\u0442(?:\u043e\u0439|\u043e\u043c\u0443)\s+(?:\u043f\u043e\u0437\u0438\u0446\u0438\u0438|\u0442\u043e\u0432\u0430\u0440\u0443))/iu.test(normalized);
if (!hasSelectedObjectCue) {
return false;
}
return /(?:\u0437\u0430\u0440\u0430\u0431\u043e\u0442|\u043f\u0440\u0438\u0431\u044b\u043b|\u043c\u0430\u0440\u0436|\u043f\u0440\u043e\u0434\u0430\u0436|\u043f\u0440\u043e\u0434\u0430\u043b|\u0437\u0430\u043a\u0443\u043f|\u043f\u043e\u043a\u0443\u043f|\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442|\u0446\u0435\u043f\u043e\u0447|profit|margin|sale|purchase|document)/iu.test(normalized);
}
function hasOrganizationLevelEarningsOverviewSignal(text) {
const normalized = String(text ?? "");
if (!normalized || hasExplicitCounterpartyValueObject(normalized)) {
return false;
}
const hasYearRankingCue = /(?:(?:\u043a\u0430\u043a\u043e\u0439|\u043a\u0430\u043a\u0438\u0435|\u043a\u0430\u043a\u0430\u044f|what|which)\s+(?:\u0443\s+\u043d\u0430\u0441\s+)?(?:[\p{L}0-9._-]+\s+){0,4}(?:\u0441\u0430\u043c|\u0441\u0430\u043c\u044b\u0435|best|top|most)[\s\S]{0,80}(?:\u0434\u043e\u0445\u043e\u0434\u043d|\u043f\u0440\u0438\u0431\u044b\u043b|\u0432\u044b\u0440\u0443\u0447\u043a|\u043e\u0431\u043e\u0440\u043e\u0442|revenue|profit|turnover)[\s\S]{0,40}(?:\u0433\u043e\u0434|year)|(?:\u0434\u043e\u0445\u043e\u0434\u043d|\u043f\u0440\u0438\u0431\u044b\u043b|\u0432\u044b\u0440\u0443\u0447\u043a|\u043e\u0431\u043e\u0440\u043e\u0442|revenue|profit|turnover)[\s\S]{0,60}(?:\u0441\u0430\u043c|\u0441\u0430\u043c\u044b\u0435|best|top|most)[\s\S]{0,40}(?:\u0433\u043e\u0434|year))/iu.test(normalized);
const hasCompanyEarningsCue = /(?:(?:\u0441\u043a\u043e\u043b\u044c\u043a\u043e|\u0441\u043a\u043e\u043a\w*|how\s+much)[\s\S]{0,120}(?:\u0437\u0430\u0440\u0430\u0431\u043e\u0442|\u0432\u044b\u0440\u0443\u0447)|(?:\u0437\u0430\u0440\u0430\u0431\u043e\u0442|\u0432\u044b\u0440\u0443\u0447)[\s\S]{0,80}(?:\u0437\u0430\s+(?:\u0432\u0441\u0435\s+\u0432\u0440\u0435\u043c\u044f|\d{2,4}\s*\u0433\u043e\u0434|(?:19|20)\d{2})|all\s+time|\b(?:19|20)\d{2}\b)|(?:\u043e\u0431\u0449\w*\s+(?:\u043e\u0431\u043e\u0440\u043e\u0442|\u0432\u044b\u0440\u0443\u0447\u043a)|(?:\u043e\u0431\u043e\u0440\u043e\u0442|\u0432\u044b\u0440\u0443\u0447\u043a)[\s\S]{0,40}\u0437\u0430\s+\u0432\u0441\u0435\s+\u0432\u0440\u0435\u043c\u044f))/iu.test(normalized);
const hasCompanyProfitMarginCue = /(?:\u043f\u0440\u0438\u0431\u044b\u043b\w*|\u043c\u0430\u0440\u0436\w*|\u0440\u0435\u043d\u0442\u0430\u0431\w*|\u0444\u0438\u043d(?:\u0430\u043d\u0441\w*)?\s*[- ]?\s*\u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442|p\s*&\s*l|profit(?:ability)?|margin|financial\s+result)/iu.test(normalized) &&
/(?:\u043a\u0430\u043a\w*|\u0441\u043a\u043e\u043b\u044c\u043a\u043e|\u0441\u043a\u043e\u043a\w*|\u043f\u043e\u043a\u0430\u0436|\u0434\u0430\u0439|\u0443\s+\u043d\u0430\u0441|\u043d\u0430\u0448\w*|\u043c\u044b\b|\u043a\u043e\u043c\u043f\u0430\u043d|\u0431\u0438\u0437\u043d\u0435\u0441|\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446|\u0432\s+\u0446\u0435\u043b\u043e\u043c|\u0432\u043e\u043e\u0431\u0449\u0435|(?:19|20)\d{2}|all\s+time|what|which|how\s+much|show|give|company|business|organization|our|we|us)/iu.test(normalized);
return hasYearRankingCue || hasCompanyEarningsCue || hasCompanyProfitMarginCue;
}
function hasOrganizationLevelDebtDueDateOverviewSignal(text) {
const normalized = String(text ?? "");
if (!normalized) {
return false;
}
if (/(?:\u043a\u0442\u043e|\u043a\u043e\u043c\u0443|\u043a\u0430\u043a\u0438\u0435\s+(?:\u043f\u043e\u043a\u0443\u043f\u0430\u0442\u0435\u043b|\u043a\u043b\u0438\u0435\u043d\u0442|\u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442|\u0437\u0430\u043a\u0430\u0437\u0447\u0438\u043a|\u0434\u043e\u043b\u0436\u043d\u0438\u043a)|who\b|which\s+(?:customers|clients|counterparties|debtors))/iu.test(normalized)) {
return false;
}
const hasDueDateDebtCue = /(?:\u043f\u0440\u043e\u0441\u0440\u043e\u0447\w*|\u0441\u0440\u043e\u043a\w*\s+\u043e\u043f\u043b\u0430\u0442|\u0441\u0440\u043e\u043a\u0438\s+\u0434\u0430\u0432\u043d\u043e\s+\u043f\u0440\u043e\u0448|\u0434\u043e\u043b\u0433\w*\s+aging|\u043a\u0430\u0447\u0435\u0441\u0442\u0432\w*\s+\u0434\u043e\u043b\u0433|\u0434\u043e\u043b\u0433\w*\s+\u043a\u0430\u0447\u0435\u0441\u0442\u0432|due[-\s]?date|overdue|debt\s+aging|debt\s+quality|credit\s+risk)/iu.test(normalized);
const hasCompanyScopeCue = /(?:\u0443\s+\u043d\u0430\u0441|\u043d\u0430\u0448\w*|\u043f\u043e\s+\u043a\u043e\u043c\u043f\u0430\u043d|\u043a\u043e\u043c\u043f\u0430\u043d|\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446|\u0431\u0438\u0437\u043d\u0435\u0441|\u0432\s+\u0446\u0435\u043b\u043e\u043c|\u043e\u0431\u0449\w*|\u043a\u0430\u043a\w*|\u043f\u043e\u043a\u0430\u0436|\u0434\u0430\u0439|\u0441\u0440\u0435\u0437|\u0430\u043d\u0430\u043b\u0438\u0437|(?:19|20)\d{2}|company|business|organization|overall|our|we|us|show|give|analysis)/iu.test(normalized);
return hasDueDateDebtCue && hasCompanyScopeCue;
}
function hasOrganizationLevelDebtPositionOverviewSignal(text) {
const normalized = String(text ?? "");
if (!normalized) {
return false;
}
const hasReceivablesCue = /(?:\u0434\u0435\u0431\u0438\u0442\u043e\u0440\w*|\u043a\u0442\u043e\s+\u043d\u0430\u043c\s+\u0434\u043e\u043b\u0436|\u043d\u0430\u043c\s+\u0434\u043e\u043b\u0436\w*|receivables?|accounts\s+receivable)/iu.test(normalized);
const hasPayablesCue = /(?:\u043a\u0440\u0435\u0434\u0438\u0442\u043e\u0440\w*|\u043a\u043e\u043c\u0443\s+\u043c\u044b\s+\u0434\u043e\u043b\u0436|\u043c\u044b\s+\u0434\u043e\u043b\u0436\w*|payables?|accounts\s+payable)/iu.test(normalized);
const hasOverviewCue = /(?:\u0441\u0440\u0435\u0437|\u043f\u043e\u0437\u0438\u0446\w*|\u0431\u0430\u043b\u0430\u043d\u0441|\u0441\u0430\u043b\u044c\u0434\u043e|\u043d\u0435\u0442\u0442\u043e|\u043d\u0430\s+\u0441\u0435\u0433\u043e\u0434\u043d|\u043d\u0430\s+\u0434\u0430\u0442\u0443|\u0443\s+\u043d\u0430\u0441|\u043f\u043e\s+\u043a\u043e\u043c\u043f\u0430\u043d|\u043a\u043e\u043c\u043f\u0430\u043d|\u0431\u0438\u0437\u043d\u0435\u0441|\u043e\u0431\u0437\u043e\u0440|\u0430\u043d\u0430\u043b\u0438\u0437|as\s+of|overview|balance|net|company|business)/iu.test(normalized);
return hasReceivablesCue && hasPayablesCue && hasOverviewCue;
}
function hasDebtClassificationFollowupSignal(text) {
const normalized = String(text ?? "");
if (!normalized) {
return false;
}
const hasClassificationCue = /(?:\u043c\u043e\u0436\u043d\u043e\s+\u043b\u0438\s+\u0441\u0447\u0438\u0442\u0430\u0442\u044c|\u044d\u0442\u043e\s+\u043c\u043e\u0436\u043d\u043e\s+\u0441\u0447\u0438\u0442\u0430\u0442\u044c|\u044d\u0442\u043e\s+\u0441\u0447\u0438\u0442\u0430\u0442\u044c|\u043a\u043b\u0430\u0441\u0441\u0438\u0444\u0438\u0446|\u0447\u0442\u043e\s+\u044d\u0442\u043e|can\s+this\s+be\s+treated)/iu.test(normalized);
const hasDebtCue = /(?:\u043f\u0440\u043e\u0441\u0440\u043e\u0447|\u043e\u0442\u043a\u0440\u044b\u0442\w*\s+\u0437\u0430\u0434\u043e\u043b\u0436|\u0434\u043e\u043b\u0433|\u0434\u0435\u0431\u0438\u0442\u043e\u0440|\u043a\u0440\u0435\u0434\u0438\u0442\u043e\u0440|overdue|open\s+debt|receivable|payable)/iu.test(normalized);
return hasClassificationCue && hasDebtCue;
}
function hasOrganizationLevelInventoryReserveLiquidationOverviewSignal(text) {
const normalized = String(text ?? "");
if (!normalized) {
return false;
}
if (/(?:\u043a\u0430\u043a\u0438\u0435\s+(?:\u0442\u043e\u0432\u0430\u0440|\u043d\u043e\u043c\u0435\u043d\u043a\u043b\u0430\u0442\u0443\u0440|\u043f\u043e\u0437\u0438\u0446)|\u0447\u0442\u043e\s+(?:\u043b\u0435\u0436\u0438\u0442|\u043d\u0430\s+\u0441\u043a\u043b\u0430\u0434)|which\s+(?:items|products|goods))/iu.test(normalized)) {
return false;
}
const hasInventoryQualityCue = /(?:\u043d\u0435\u043b\u0438\u043a\u0432\u0438\u0434\w*|\u0440\u0435\u0437\u0435\u0440\u0432\w*|\u0441\u043f\u0438\u0441\u0430\u043d\w*|\u043b\u0438\u043a\u0432\u0438\u0434\u0430\u0446\w*|\u0443\u0441\u0442\u0430\u0440\u0435\u0432\w*|\u043e\u0431\u0435\u0441\u0446\u0435\u043d\w*|obsolete|obsolescence|reserve|write[-\s]?off|liquidation|inventory\s+quality|stock\s+quality)/iu.test(normalized);
const hasInventoryScopeCue = /(?:\u0441\u043a\u043b\u0430\u0434|\u043e\u0441\u0442\u0430\u0442|\u0437\u0430\u043f\u0430\u0441|\u0442\u043e\u0432\u0430\u0440|\u043d\u043e\u043c\u0435\u043d\u043a\u043b\u0430\u0442\u0443\u0440|inventory|stock|warehouse)/iu.test(normalized);
const hasCompanyScopeCue = /(?:\u0443\s+\u043d\u0430\u0441|\u043d\u0430\u0448\w*|\u043f\u043e\s+\u043a\u043e\u043c\u043f\u0430\u043d|\u043a\u043e\u043c\u043f\u0430\u043d|\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446|\u0431\u0438\u0437\u043d\u0435\u0441|\u0432\s+\u0446\u0435\u043b\u043e\u043c|\u043e\u0431\u0449\w*|\u0441\u043a\u043b\u0430\u0434|\u043e\u0441\u0442\u0430\u0442|\u0437\u0430\u043f\u0430\u0441|\u043a\u0430\u043a\w*|\u043f\u043e\u043a\u0430\u0436|\u0434\u0430\u0439|\u0441\u0440\u0435\u0437|\u0430\u043d\u0430\u043b\u0438\u0437|(?:19|20)\d{2}|company|business|organization|overall|warehouse|stock|inventory|our|we|us|show|give|analysis)/iu.test(normalized);
return hasInventoryQualityCue && hasInventoryScopeCue && hasCompanyScopeCue;
}
function hasOrganizationLevelSupplierQualityOverviewSignal(text) {
const normalized = String(text ?? "");
if (!normalized) {
return false;
}
if (/(?:\u0445\u0432\u043e\u0441\u0442|\u0434\u043e\u043b\u0433|\u0437\u0430\u0434\u043e\u043b\u0436|\u0441\u0430\u043b\u044c\u0434\u043e|\u043e\u043f\u043b\u0430\u0442|\u043f\u043b\u0430\u0442[\u0435\u0451]\u0436|\u0430\u043a\u0442|\u043f\u0440\u0438\u0445\u043e\u0434|\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442|\b60\b|open\s+items?|payable|payment|invoice|bill|settlement|reconciliation)/iu.test(normalized)) {
return false;
}
const hasSupplierScopeCue = /(?:\u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a|\u0432\u0435\u043d\u0434\u043e\u0440|\u0437\u0430\u043a\u0443\u043f|\u0441\u043d\u0430\u0431\u0436|supplier|vendor|procurement|sourcing)/iu.test(normalized);
const hasSupplierQualityCue = /(?:\u0440\u0438\u0441\u043a\w*|\u043a\u0430\u0447\u0435\u0441\u0442\u0432\w*|\u043f\u0440\u043e\u0431\u043b\u0435\u043c\w*|\u0437\u0430\u0432\u0438\u0441\u0438\w*|\u0437\u0430\u0432\u044f\u0437\u0430\u043d\w*|\u043a\u043e\u043d\u0446\u0435\u043d\u0442\u0440\u0430\u0446\w*|\u043a\u043b\u044e\u0447\u0435\u0432\w*|\u043a\u0440\u0438\u0442\u0438\u0447\w*|risk|quality|problem|dependency|concentration|critical|key\s+supplier)/iu.test(normalized);
const hasCompanyScopeCue = /(?:\u0443\s+\u043d\u0430\u0441|\u043d\u0430\u0448\w*|\u043f\u043e\s+\u043a\u043e\u043c\u043f\u0430\u043d|\u043a\u043e\u043c\u043f\u0430\u043d|\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446|\u0431\u0438\u0437\u043d\u0435\u0441|\u0432\s+\u0446\u0435\u043b\u043e\u043c|\u043e\u0431\u0449\w*|\u043a\u0430\u043a\w*|\u043f\u043e\u043a\u0430\u0436|\u0434\u0430\u0439|\u0441\u0440\u0435\u0437|\u0430\u043d\u0430\u043b\u0438\u0437|(?:19|20)\d{2}|company|business|organization|overall|our|we|us|show|give|analysis)/iu.test(normalized);
return hasSupplierScopeCue && hasSupplierQualityCue && hasCompanyScopeCue;
}
function hasOrganizationLevelMoneyBreakdownSignal(text) {
const normalized = String(text ?? "");
if (!normalized) {
return false;
}
const hasIncomingCue = /(?:\u043f\u043e\u043b\u0443\u0447|\u0432\u0445\u043e\u0434\u044f\u0449|\u043f\u043e\u0441\u0442\u0443\u043f|\u043a\u043b\u0438\u0435\u043d\u0442|received|incoming|customer)/iu.test(normalized);
const hasOutgoingCue = /(?:\u0437\u0430\u043f\u043b\u0430\u0442|\u0438\u0441\u0445\u043e\u0434\u044f\u0449|\u0441\u043f\u0438\u0441\u0430\u043d|\u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a|paid|outgoing|supplier)/iu.test(normalized);
const hasNetCue = /(?:\u043d\u0435\u0442\u0442\u043e|\u0447\u0438\u0441\u0442\p{L}*\s+\u0434\u0435\u043d\u0435\u0436\u043d\p{L}*\s+\u043f\u043e\u0442\u043e\u043a|net\s+(?:cash|flow)|cash\s+flow)/iu.test(normalized);
const hasRankingCue = /(?:\u0433\u043b\u0430\u0432\u043d\p{L}*\s+(?:\u043a\u043b\u0438\u0435\u043d\u0442|\u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a)|top\s+(?:customer|supplier))/iu.test(normalized);
const hasBreakdownCue = /(?:\u0440\u0430\u0441\u043a\u0440\u043e\p{L}*|\u043f\u043e\u0434\u0440\u043e\u0431\u043d|\u0441\u043a\u043e\u043b\u044c\u043a\u043e\s+\u0432\u0441\u0435\u0433\u043e|\u0441\u0432\u043e\u0434\p{L}*|breakdown|detail)/iu.test(normalized);
return hasBreakdownCue && hasIncomingCue && hasOutgoingCue && (hasNetCue || hasRankingCue);
}
function detectBroadBusinessEvaluation(text) {
const normalized = String(text ?? "");
if (!normalized) {
return null;
}
if (/(?:\u0431\u0438\u0437\u043d\u0435\u0441[-\s]?\u043e\u0431\u0437\u043e\u0440|\u0431\u0438\u0437\u043d\u0435\u0441[-\s]?\u0430\u0443\u0434\u0438\u0442|\u043f\u043e\u043b\u043d\w*\s+\u0430\u043d\u0430\u043b\u0438\u0437\s+(?:\u043a\u043e\u043c\u043f\u0430\u043d|\u0431\u0438\u0437\u043d\u0435\u0441|\u0434\u0435\u044f\u0442\u0435\u043b)|\u0441\u0432\u043e\u0434\u043d\w*\s+\u0430\u043d\u0430\u043b\u0438\u0437\s+(?:\u043a\u043e\u043c\u043f\u0430\u043d|\u0431\u0438\u0437\u043d\u0435\u0441|\u0434\u0435\u044f\u0442\u0435\u043b)|\u043a\u0430\u043a\s+\u0442\u044b\s+\u043e\u0446\u0435\u043d(?:\u0438\u0448\u044c|\u0438)\s+\u0434\u0435\u044f\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442|\u043a\u043e\u043c\u043f\u0430\u043d(?:\u0438\u0438|\u0438\u044e|\u0438\u044f)\s+\u0432\s+\u0446\u0435\u043b\u043e\u043c|company\s+(?:analysis|overview)|business\s+(?:overview|audit)|llm[-\s]?audit|бизнес[-\s]?обзор|бизнес[-\s]?аудит)/iu.test(normalized)) {
return {
family: "broad_business_evaluation"
};
}
if (/(?:как\s+ты\s+оценишь\s+деятельност[ьи]\s+компан|оценк[аи]?\s+деятельност[ьи]\s+компан|оцени\s+(?:компан|бизнес|деятельност)|(?:полный|сводный|нормальн\w*|взросл\w*)\s+анализ\s+(?:компан|бизнес|деятельност)|проанализируй\s+(?:компан|бизнес|деятельност)|(?:что\s+думаешь|какое\s+мнение)\s+(?:о|по)\s+(?:компан|бизнес)|(?:llm[-\s]?)?аудит\s+(?:компан|бизнес)|что\s+у\s+нас\s+вообще\s+происход|где\s+главн(?:ые|ый)\s+риски|как\s+у\s+нас\s+дела\s+по\s+компан)/iu.test(normalized)) {
return {
family: "broad_business_evaluation"
};
}
if (hasOrganizationLevelEarningsOverviewSignal(normalized)) {
return {
family: "broad_business_evaluation"
};
}
if (hasOrganizationLevelDebtDueDateOverviewSignal(normalized)) {
return {
family: "broad_business_evaluation"
};
}
if (hasOrganizationLevelDebtPositionOverviewSignal(normalized)) {
return {
family: "broad_business_evaluation"
};
}
if (hasDebtClassificationFollowupSignal(normalized)) {
return {
family: "broad_business_evaluation"
};
}
if (hasOrganizationLevelInventoryReserveLiquidationOverviewSignal(normalized)) {
return {
family: "broad_business_evaluation"
};
}
if (hasOrganizationLevelSupplierQualityOverviewSignal(normalized)) {
return {
family: "broad_business_evaluation"
};
}
if (hasOrganizationLevelMoneyBreakdownSignal(normalized)) {
return {
family: "broad_business_evaluation"
};
}
return null;
}
function buildEntityCandidates(entityFamily) {
if (!entityFamily?.entity) {
return [];
}
return [
{
type: "counterparty",
value: entityFamily.entity,
source: "current_turn_loose_entity_tail"
}
];
}
function createAssistantTurnMeaningPolicy(deps = {}) {
function resolveAssistantTurnMeaning(input = {}) {
const rawMessage = String(input?.rawUserMessage ?? input?.userMessage ?? "");
const effectiveMessage = String(input?.effectiveAddressUserMessage ?? rawMessage);
const rawText = normalizeTurnText(rawMessage, deps);
const effectiveText = normalizeTurnText(effectiveMessage, deps);
const joinedText = fallbackCompactWhitespace(`${rawText} ${effectiveText}`);
const compactOrganizationCashflowDisplay = hasCompactOrganizationCashflowDisplaySignal(rawText);
const supportedIntent = compactOrganizationCashflowDisplay ? null : detectSupportedIntent(joinedText, deps);
const counterpartyBidirectionalValueFlow = compactOrganizationCashflowDisplay ? null : detectCounterpartyBidirectionalValueFlowFamily(joinedText);
const counterpartyTurnover = compactOrganizationCashflowDisplay ? null : detectCounterpartyTurnoverFamily(joinedText);
const selectedObjectInventoryExact = hasSelectedObjectInventoryExactSignal(joinedText);
const broadBusinessEvaluation = compactOrganizationCashflowDisplay
? { family: "broad_business_evaluation" }
: selectedObjectInventoryExact || counterpartyBidirectionalValueFlow?.family
? null
: detectBroadBusinessEvaluation(joinedText);
const llmIntent = toNonEmptyString(input?.llmPreDecomposeMeta?.predecomposeContract?.intent, deps);
const explicitIntentCandidate = broadBusinessEvaluation?.family
? null
: supportedIntent?.intent ?? (llmIntent && llmIntent !== "unknown" ? llmIntent : null);
const unsupportedFamily = broadBusinessEvaluation?.family
? broadBusinessEvaluation.family
: !explicitIntentCandidate && counterpartyBidirectionalValueFlow?.family
? counterpartyBidirectionalValueFlow.family
: !explicitIntentCandidate && counterpartyTurnover?.family
? counterpartyTurnover.family
: null;
const reasonCodes = [];
if (supportedIntent?.reason) {
reasonCodes.push(supportedIntent.reason);
}
if (counterpartyBidirectionalValueFlow?.family) {
reasonCodes.push("counterparty_bidirectional_value_flow_current_turn_signal");
}
if (counterpartyTurnover?.family) {
reasonCodes.push("counterparty_turnover_current_turn_signal");
}
if (broadBusinessEvaluation?.family) {
reasonCodes.push("broad_business_evaluation_current_turn_signal");
}
if (compactOrganizationCashflowDisplay) {
reasonCodes.push("compact_cashflow_display_current_turn_signal");
}
if (rawText !== normalizeTurnText(rawMessage, { ...deps, repairAddressMojibake: (value) => String(value ?? "") })) {
reasonCodes.push("mojibake_repair_applied");
}
if (rawText.includes("\u043d\u0430\u043c") &&
/(^|[^\p{L}0-9_])\u043d\u0430\u043c\u0441(?=$|[^\p{L}0-9_])/iu.test(String(rawMessage ?? ""))) {
reasonCodes.push("known_turn_typo_normalized");
}
const askedDomainFamily = explicitIntentCandidate?.startsWith("receivables_")
? "receivables"
: explicitIntentCandidate?.startsWith("payables_")
? "payables"
: explicitIntentCandidate?.startsWith("vat_")
? "vat"
: explicitIntentCandidate?.startsWith("inventory_")
? "inventory"
: broadBusinessEvaluation?.family
? "business_summary"
: counterpartyBidirectionalValueFlow?.family
? "counterparty_value"
: explicitIntentCandidate?.includes("counterparty")
? "counterparty"
: counterpartyTurnover?.family
? "counterparty"
: null;
const askedActionFamily = explicitIntentCandidate === "receivables_confirmed_as_of_date" ||
explicitIntentCandidate === "payables_confirmed_as_of_date" ||
explicitIntentCandidate === "inventory_on_hand_as_of_date"
? "confirmed_snapshot"
: broadBusinessEvaluation?.family
? "broad_evaluation"
: counterpartyBidirectionalValueFlow?.family
? "net_value_flow"
: explicitIntentCandidate === "customer_revenue_and_payments" ||
explicitIntentCandidate === "supplier_payouts_profile"
? "counterparty_value_or_turnover"
: explicitIntentCandidate === "vat_liability_confirmed_for_tax_period"
? "confirmed_tax_period"
: explicitIntentCandidate === "vat_payable_confirmed_as_of_date"
? "confirmed_snapshot"
: explicitIntentCandidate === "vat_payable_forecast"
? "forecast"
: explicitIntentCandidate === "list_documents_by_counterparty"
? "list_documents"
: counterpartyTurnover?.family
? "counterparty_value_or_turnover"
: null;
const staleReplayForbidden = Boolean(unsupportedFamily ||
broadBusinessEvaluation?.family ||
(counterpartyBidirectionalValueFlow?.entity && !explicitIntentCandidate) ||
(counterpartyTurnover?.entity && !explicitIntentCandidate));
return {
schema_version: "assistant_turn_meaning_v1",
raw_message: rawMessage,
effective_message: effectiveMessage,
normalized_raw_message: rawText,
normalized_effective_message: effectiveText,
asked_domain_family: askedDomainFamily,
asked_action_family: askedActionFamily,
explicit_intent_candidate: explicitIntentCandidate,
explicit_entity_candidates: broadBusinessEvaluation?.family
? []
: buildEntityCandidates(counterpartyBidirectionalValueFlow ?? counterpartyTurnover),
meaning_confidence: broadBusinessEvaluation?.family
? "medium"
: supportedIntent?.confidence ??
(counterpartyBidirectionalValueFlow?.family || counterpartyTurnover?.family ? "medium" : "low"),
intent_override_strength: explicitIntentCandidate
? "explicit_current_turn_intent"
: staleReplayForbidden
? "explicit_new_action_or_entity"
: "none",
carryover_budget: staleReplayForbidden ? "none" : explicitIntentCandidate ? "matching_family_only" : "normal",
unsupported_but_understood_family: unsupportedFamily,
stale_replay_forbidden: staleReplayForbidden,
reason_codes: reasonCodes
};
}
return {
resolveAssistantTurnMeaning
};
}