"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.buildAssistantAddressOrchestrationRuntime = buildAssistantAddressOrchestrationRuntime; const assistantRoutePolicyRuntimeAdapter_1 = require("./assistantRoutePolicyRuntimeAdapter"); const assistantMcpDiscoveryRuntimeEntryPoint_1 = require("./assistantMcpDiscoveryRuntimeEntryPoint"); const inventoryLifecycleCueHelpers_1 = require("./inventoryLifecycleCueHelpers"); function toRecordObject(value) { if (!value || typeof value !== "object" || Array.isArray(value)) { return null; } return value; } function sessionOrganizationName(sessionOrganizationScope, toNonEmptyString) { const scope = toRecordObject(sessionOrganizationScope); return toNonEmptyString(scope?.selectedOrganization) ?? toNonEmptyString(scope?.activeOrganization); } function sessionKnownOrganizations(sessionOrganizationScope) { const scope = toRecordObject(sessionOrganizationScope); const knownOrganizations = scope?.knownOrganizations; return Array.isArray(knownOrganizations) ? knownOrganizations : []; } function predecomposeOrganizationName(predecomposeContract, toNonEmptyString) { const entities = toRecordObject(predecomposeContract?.entities); return (toNonEmptyString(entities?.organization) ?? toNonEmptyString(predecomposeContract?.organization)); } function mergeOrganizationIntoDiscoveryFollowupContext(followupContext, organization) { if (!organization) { return followupContext; } const base = followupContext ? { ...followupContext } : {}; const previousFilters = toRecordObject(base.previous_filters) ? { ...base.previous_filters } : {}; if (!previousFilters.organization) { previousFilters.organization = organization; } base.previous_filters = previousFilters; const rootFilters = toRecordObject(base.root_filters) ? { ...base.root_filters } : {}; if (!rootFilters.organization) { rootFilters.organization = organization; } base.root_filters = rootFilters; if (!base.previous_anchor_type) { base.previous_anchor_type = "organization"; } if (!base.previous_anchor_value) { base.previous_anchor_value = organization; } return base; } function compactLower(value) { return String(value ?? "") .toLowerCase() .replace(/\s+/g, " ") .trim(); } function hasCompactCashflowFollowupSignal(text) { const value = compactLower(text); if (!value) { return false; } return /(?:\u0431\u0435\u0437\s+\u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\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+\u0434\u0435\u0442\u0430\u043b\p{L}*|\u043e\u0434\u043d\u043e\u0439\s+\u0441\u0442\u0440\u043e\u043a\p{L}*|\u0442\u043e\u043b\u044c\u043a\u043e\s+\u0438\u0442\u043e\u0433|\u043f\u0440\u0438\u0448\p{L}*[\s\S]{0,80}\u0443\u0448\p{L}*[\s\S]{0,80}\u043d\u0435\u0442\u0442\u043e|\u043f\u043e\u043b\u0443\u0447\p{L}*[\s\S]{0,80}\u0437\u0430\u043f\u043b\u0430\u0442\p{L}*[\s\S]{0,80}\u0431\u0435\u0437\s+\u0434\u0435\u0442\u0430\u043b|кто\s+больше\s+всего\s+зан[её]с|кому\s+больше\s+всего\s+ушл\p{L}*|банк\s+не\s+называй\s+обычн\p{L}*\s+клиент\p{L}*|главн\p{L}*\s+клиент|главн\p{L}*\s+поставщик)/iu.test(value); } function dateScopeToFilterWindow(dateScope) { if (!dateScope) { return null; } if (/^(?:19|20)\d{2}$/.test(dateScope)) { return { period_from: `${dateScope}-01-01`, period_to: `${dateScope}-12-31` }; } if (/^(?:19|20)\d{2}-\d{2}-\d{2}$/.test(dateScope)) { return { as_of_date: dateScope }; } return null; } function filterWindowFromExtractedFilters(filters) { if (!filters) { return null; } const asOfDate = typeof filters.as_of_date === "string" ? filters.as_of_date.trim() : ""; if (/^(?:19|20)\d{2}-\d{2}-\d{2}$/.test(asOfDate)) { return { as_of_date: asOfDate }; } const periodFrom = typeof filters.period_from === "string" ? filters.period_from.trim() : ""; const periodTo = typeof filters.period_to === "string" ? filters.period_to.trim() : ""; if (/^(?:19|20)\d{2}-\d{2}-\d{2}$/.test(periodFrom) && /^(?:19|20)\d{2}-\d{2}-\d{2}$/.test(periodTo)) { return { period_from: periodFrom, period_to: periodTo }; } return null; } function hasBoundedFilterWindow(filters) { if (!filters) { return false; } if (typeof filters.as_of_date === "string" && /^(?:19|20)\d{2}-\d{2}-\d{2}$/.test(filters.as_of_date.trim())) { return true; } const periodFrom = typeof filters.period_from === "string" ? filters.period_from.trim() : ""; const periodTo = typeof filters.period_to === "string" ? filters.period_to.trim() : ""; return /^(?:19|20)\d{2}-\d{2}-\d{2}$/.test(periodFrom) && /^(?:19|20)\d{2}-\d{2}-\d{2}$/.test(periodTo); } function looksLikeReliableOrganizationScope(value) { const text = compactLower(value); if (!text) { return false; } if (/(?:\u0440\u0430\u0437\u0431\u0438\u0432|\u0440\u0430\u0437\u0440\u0435\u0437|\u0432\u0445\u043e\u0434\u044f\u0449|\u0438\u0441\u0445\u043e\u0434\u044f\u0449|\u043d\u0435\u0442\u0442\u043e|\u0442\u043e\u043f)/iu.test(text)) { return false; } return /(?:^|[\s"'\u00ab])(?:\u043e\u043e\u043e|\u0438\u043f|\u043f\u0430\u043e|\u0430\u043e|\u0437\u0430\u043e)(?:[\s"'\u00bb]|$)|\u043e\u0431\u0449\u0435\u0441\u0442\u0432\p{L}*\s+\u0441\s+\u043e\u0433\u0440\u0430\u043d\u0438\u0447\p{L}*\s+\u043e\u0442\u0432\p{L}*|\b(?:llc|inc|corp)\b/iu.test(text); } function inferBusinessOverviewDiscoveryContextFromSessionItems(sessionItems, toNonEmptyString) { for (let index = sessionItems.length - 1; index >= 0; index -= 1) { const item = toRecordObject(sessionItems[index]); if (toNonEmptyString(item?.role) !== "assistant") { continue; } const debug = toRecordObject(item?.debug); const entryPoint = toRecordObject(debug?.assistant_mcp_discovery_entry_point_v1); const turnInput = toRecordObject(entryPoint?.turn_input); const dataNeedGraph = toRecordObject(turnInput?.data_need_graph); if (toNonEmptyString(dataNeedGraph?.business_fact_family) !== "business_overview") { continue; } const turnMeaningRef = toRecordObject(turnInput?.turn_meaning_ref); const debugFilters = toRecordObject(debug?.extracted_filters); const filterWindow = dateScopeToFilterWindow(toNonEmptyString(turnMeaningRef?.explicit_date_scope)) ?? filterWindowFromExtractedFilters(debugFilters); if (!filterWindow) { continue; } const previousFilters = { ...filterWindow }; const organization = toNonEmptyString(turnMeaningRef?.explicit_organization_scope) ?? toNonEmptyString(debugFilters?.organization); if (looksLikeReliableOrganizationScope(organization)) { previousFilters.organization = organization; } const rankingNeed = toNonEmptyString(dataNeedGraph?.ranking_need); return { previous_discovery_pilot_scope: "business_overview_route_template_v1", previous_filters: previousFilters, root_filters: { ...previousFilters }, previous_seeded_ranking_need: rankingNeed, previous_intent: "business_overview", root_intent: "business_overview" }; } return null; } function mergeBusinessOverviewDateContextForCompactCashflow(input) { if (!hasCompactCashflowFollowupSignal(input.userMessage)) { return input.followupContext; } const existingFilters = toRecordObject(input.followupContext?.previous_filters); if (hasBoundedFilterWindow(existingFilters)) { return input.followupContext; } const inferred = inferBusinessOverviewDiscoveryContextFromSessionItems(input.sessionItems, input.toNonEmptyString); if (!inferred) { return input.followupContext; } return { ...inferred, ...(input.followupContext ?? {}), previous_filters: { ...(toRecordObject(input.followupContext?.previous_filters) ?? {}), ...(toRecordObject(inferred.previous_filters) ?? {}) }, root_filters: { ...(toRecordObject(input.followupContext?.root_filters) ?? {}), ...(toRecordObject(inferred.root_filters) ?? {}) } }; } function firstString(values, toNonEmptyString) { for (const value of values) { const text = toNonEmptyString(value); if (text) { return text; } } return null; } function comparableEntityName(value) { const text = compactLower(value); return text ? text.replace(/["'«»„“”]+/g, "") : null; } function sameEntityHint(expected, actual) { const left = comparableEntityName(expected); const right = comparableEntityName(actual); if (!left || !right) { return true; } return left === right || left.includes(right) || right.includes(left); } function hasComparisonScopeProofCue(text) { const value = compactLower(text); if (!value) { return false; } return /(?:\bсравни\b|собери\s+коротк\p{L}*\s+итог|коротк\p{L}*\s+сравн|что\s+.*подтверд\p{L}*.*(?:компан|контрагент|свк)|что\s+.*отдельно\s+по\s+(?:группа\s+свк|выбранн\p{L}*\s+контрагент)|какие\s+выводы\s+можно\s+делать\s+и\s+какие\s+нельзя)/iu.test(value); } function isBusinessOverviewDiscoveryFollowup(followupContext, toNonEmptyString) { if (!followupContext) { return false; } return [ followupContext.previous_discovery_pilot_scope, followupContext.previous_discovery_loop_selected_chain_id, followupContext.previous_discovery_loop_asked_domain_family, followupContext.previous_intent, followupContext.target_intent ] .map((value) => toNonEmptyString(value)) .some((value) => value === "business_overview" || value === "business_overview_route_template_v1"); } function businessOverviewCounterpartyHint(followupContext, toNonEmptyString) { const previousFilters = toRecordObject(followupContext.previous_filters); const rootFilters = toRecordObject(followupContext.root_filters); return (toNonEmptyString(followupContext.previous_discovery_loop_metadata_scope_hint) ?? (toNonEmptyString(followupContext.previous_anchor_type) === "counterparty" ? toNonEmptyString(followupContext.previous_anchor_value) : null) ?? toNonEmptyString(previousFilters?.counterparty) ?? toNonEmptyString(rootFilters?.counterparty)); } function turnMeaningCounterpartyName(turnMeaningRef, valueBundle, documentBundle, toNonEmptyString) { const separateEntities = Array.isArray(turnMeaningRef.business_overview_separate_entity_candidates) ? turnMeaningRef.business_overview_separate_entity_candidates : []; return (toNonEmptyString(valueBundle?.counterparty) ?? toNonEmptyString(documentBundle?.counterparty) ?? toNonEmptyString(turnMeaningRef.metadata_scope_hint) ?? firstString(separateEntities, toNonEmptyString)); } function parseBusinessOverviewProofBundlesFromText(value, toNonEmptyString) { const text = toNonEmptyString(value); if (!text) { return null; } const valueMatch = text.match(/Отдельно\s+по\s+контрагенту\s+([^:\n]+):\s*подтверждено\s+получили\s+([^,\n]+?руб\.?),\s*заплатили\s+([^,\n]+?руб\.?),\s*расчетное\s+нетто\s+в\s+нашу\s+сторону\s+([^.\n]+?руб\.?)/iu); const directDocumentMatch = text.match(/Контрагент:\s*([^.\n]+)\.\s*Найдено\s+документов:\s*(\d+)/iu); const summaryDocumentMatch = text.match(/документы\s+по\s+цепочке:\s*найдено\s*(\d+)/iu); const counterparty = toNonEmptyString(valueMatch?.[1]) ?? toNonEmptyString(directDocumentMatch?.[1]); if (!counterparty) { return null; } const valueBundle = valueMatch ? { counterparty, incoming_customer_revenue: { total_amount_human_ru: toNonEmptyString(valueMatch[2]) }, outgoing_supplier_payout: { total_amount_human_ru: toNonEmptyString(valueMatch[3]) }, net_amount_human_ru: toNonEmptyString(valueMatch[4]), net_direction: "net_incoming", inference_basis: "parsed_from_previous_business_overview_summary" } : null; const documentCount = Number(directDocumentMatch?.[2] ?? summaryDocumentMatch?.[1]); const documentBundle = Number.isFinite(documentCount) && documentCount > 0 ? { counterparty, document_count: documentCount } : null; return valueBundle || documentBundle ? { valueBundle, documentBundle } : null; } function parseBusinessOverviewProofBundlesFromTextV2(value, counterpartyHint, toNonEmptyString) { const text = toNonEmptyString(value); if (!text) { return null; } const comparableHint = comparableEntityName(counterpartyHint); const lines = text .split(/\r?\n/u) .map((line) => line.trim()) .filter(Boolean); const candidateLines = comparableHint ? lines.filter((line) => comparableEntityName(line)?.includes(comparableHint)) : lines; const rubAmountPattern = /[0-9][0-9\s.,]*\s*\u0440\u0443\u0431\.?/giu; const valueLine = candidateLines.find((line) => (line.match(rubAmountPattern) ?? []).length >= 3) ?? null; const valueAmounts = valueLine?.match(rubAmountPattern) ?? []; const directDocumentMatch = candidateLines .map((line) => line.match(/\u041a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442:\s*([^.\n]+)\.\s*\u041d\u0430\u0439\u0434\u0435\u043d\u043e\s+\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u043e\u0432:\s*(\d+)/iu)) .find(Boolean); const summaryDocumentMatch = candidateLines .map((line) => line.match(/\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u044b\s+\u043f\u043e\s+\u0446\u0435\u043f\u043e\u0447\u043a\u0435:\s*\u043d\u0430\u0439\u0434\u0435\u043d\u043e\s*(\d+)/iu)) .find(Boolean); const counterparty = counterpartyHint ?? toNonEmptyString(directDocumentMatch?.[1]); if (!counterparty) { return null; } const valueBundle = valueAmounts.length >= 3 ? { counterparty, incoming_customer_revenue: { total_amount_human_ru: toNonEmptyString(valueAmounts[0]) }, outgoing_supplier_payout: { total_amount_human_ru: toNonEmptyString(valueAmounts[1]) }, net_amount_human_ru: toNonEmptyString(valueAmounts[2]), net_direction: "net_incoming", inference_basis: "parsed_from_previous_business_overview_summary" } : null; const documentCount = Number(directDocumentMatch?.[2] ?? summaryDocumentMatch?.[1]); const documentBundle = Number.isFinite(documentCount) && documentCount > 0 ? { counterparty, document_count: documentCount } : null; return valueBundle || documentBundle ? { valueBundle, documentBundle } : null; } function findRecentBusinessOverviewProofBundles(input) { if (!input.counterpartyHint) { return null; } for (let index = input.sessionItems.length - 1; index >= 0; index -= 1) { const item = toRecordObject(input.sessionItems[index]); if (input.toNonEmptyString(item?.role) !== "assistant") { continue; } const debug = toRecordObject(item?.debug); const entryPoint = toRecordObject(debug?.assistant_mcp_discovery_entry_point_v1); const turnInput = toRecordObject(entryPoint?.turn_input); const turnMeaningRef = toRecordObject(turnInput?.turn_meaning_ref); if (turnMeaningRef) { const valueBundle = toRecordObject(turnMeaningRef.previous_counterparty_value_flow_bundle); const documentBundle = toRecordObject(turnMeaningRef.previous_counterparty_document_bundle); if (valueBundle || documentBundle) { const bundleCounterparty = turnMeaningCounterpartyName(turnMeaningRef, valueBundle, documentBundle, input.toNonEmptyString); if (sameEntityHint(input.counterpartyHint, bundleCounterparty)) { return { valueBundle, documentBundle }; } } } const parsedBundles = parseBusinessOverviewProofBundlesFromTextV2(item?.text, input.counterpartyHint, input.toNonEmptyString) ?? parseBusinessOverviewProofBundlesFromText(item?.text, input.toNonEmptyString); if (!parsedBundles) { continue; } const parsedCounterparty = input.toNonEmptyString(parsedBundles.valueBundle?.counterparty) ?? input.toNonEmptyString(parsedBundles.documentBundle?.counterparty); if (!sameEntityHint(input.counterpartyHint, parsedCounterparty)) { continue; } return parsedBundles; } return null; } function mergeBusinessOverviewProofBundlesFromNavigationState(input) { const currentValueBundle = toRecordObject(input.followupContext?.previous_discovery_bidirectional_value_flow); const currentDocumentBundle = toRecordObject(input.followupContext?.previous_discovery_document_summary); if (currentValueBundle && currentDocumentBundle) { return input.followupContext; } const state = toRecordObject(input.sessionAddressNavigationState); const sessionContext = toRecordObject(state?.session_context); const comparisonScope = toRecordObject(sessionContext?.comparison_scope); const proofBundles = toRecordObject(comparisonScope?.proof_bundles); const valueBundle = toRecordObject(proofBundles?.counterparty_value_flow_bundle); const documentBundle = toRecordObject(proofBundles?.counterparty_document_bundle); if (!valueBundle && !documentBundle) { return input.followupContext; } const entities = toRecordObject(input.predecomposeContract?.entities); const hasCurrentOrganizationSelection = Boolean(input.toNonEmptyString(entities?.organization)); const businessOverviewFollowup = isBusinessOverviewDiscoveryFollowup(input.followupContext, input.toNonEmptyString); if (!hasComparisonScopeProofCue(input.userMessage)) { return input.followupContext; } if (!businessOverviewFollowup && !hasCurrentOrganizationSelection) { return input.followupContext; } const comparisonCounterparty = toRecordObject(comparisonScope?.counterparty); const counterpartyHint = (input.followupContext ? businessOverviewCounterpartyHint(input.followupContext, input.toNonEmptyString) : null) ?? input.toNonEmptyString(comparisonCounterparty?.label); const bundleCounterparty = input.toNonEmptyString(valueBundle?.counterparty) ?? input.toNonEmptyString(documentBundle?.counterparty); if (!counterpartyHint || !sameEntityHint(counterpartyHint, bundleCounterparty)) { return input.followupContext; } return { ...(input.followupContext ?? {}), previous_intent: input.toNonEmptyString(input.followupContext?.previous_intent) ?? "business_overview", target_intent: input.toNonEmptyString(input.followupContext?.target_intent) ?? "business_overview", previous_discovery_pilot_scope: input.toNonEmptyString(input.followupContext?.previous_discovery_pilot_scope) ?? "business_overview_route_template_v1", previous_discovery_loop_status: input.toNonEmptyString(input.followupContext?.previous_discovery_loop_status) ?? "awaiting_clarification", previous_discovery_loop_selected_chain_id: input.toNonEmptyString(input.followupContext?.previous_discovery_loop_selected_chain_id) ?? "business_overview", previous_discovery_loop_pending_axes: Array.isArray(input.followupContext?.previous_discovery_loop_pending_axes) ? input.followupContext?.previous_discovery_loop_pending_axes : ["organization"], previous_discovery_loop_asked_domain_family: input.toNonEmptyString(input.followupContext?.previous_discovery_loop_asked_domain_family) ?? "business_overview", previous_discovery_loop_asked_action_family: input.toNonEmptyString(input.followupContext?.previous_discovery_loop_asked_action_family) ?? "broad_evaluation", previous_discovery_loop_metadata_scope_hint: input.toNonEmptyString(input.followupContext?.previous_discovery_loop_metadata_scope_hint) ?? counterpartyHint, previous_anchor_type: input.toNonEmptyString(input.followupContext?.previous_anchor_type) ?? "counterparty", previous_anchor_value: input.toNonEmptyString(input.followupContext?.previous_anchor_value) ?? counterpartyHint, previous_filters: toRecordObject(input.followupContext?.previous_filters) ?? {}, previous_discovery_bidirectional_value_flow: currentValueBundle ?? valueBundle ?? undefined, previous_discovery_document_summary: currentDocumentBundle ?? documentBundle ?? undefined }; } function mergeBusinessOverviewProofBundlesFromSessionItems(input) { if (!hasComparisonScopeProofCue(input.userMessage)) { return input.followupContext; } if (!isBusinessOverviewDiscoveryFollowup(input.followupContext, input.toNonEmptyString)) { return input.followupContext; } const currentValueBundle = toRecordObject(input.followupContext?.previous_discovery_bidirectional_value_flow); const currentDocumentBundle = toRecordObject(input.followupContext?.previous_discovery_document_summary); if (currentValueBundle && currentDocumentBundle) { return input.followupContext; } const counterpartyHint = input.followupContext ? businessOverviewCounterpartyHint(input.followupContext, input.toNonEmptyString) : null; const proofBundles = findRecentBusinessOverviewProofBundles({ sessionItems: input.sessionItems, counterpartyHint, toNonEmptyString: input.toNonEmptyString }); if (!proofBundles) { return input.followupContext; } return { ...(input.followupContext ?? {}), previous_discovery_bidirectional_value_flow: currentValueBundle ?? proofBundles.valueBundle ?? undefined, previous_discovery_document_summary: currentDocumentBundle ?? proofBundles.documentBundle ?? undefined }; } function hasSelectedObjectInventorySignal(text) { return /(?:по\s+выбранному\s+объекту|по\s+выбранной\s+позиции|по\s+этой\s+позиции|по\s+этому\s+товару|по\s+ним|selected\s+object)/iu.test(String(text ?? "")); } function hasSelectedObjectInventoryActionCue(text) { const value = String(text ?? ""); return (/(?:кому[\s\S]{0,80}(?:продал[аи]?|реализова[нлт][а-я]*|поставил[аи]?|поставлен[а-я]*|отгрузил[аи]?|отгружен[а-я]*)|кому\s+был\s+продан|куда[\s\S]{0,80}(?:продал[аи]?|реализова[нлт][а-я]*|поставил[аи]?|поставлен[а-я]*|отгрузил[аи]?|отгружен[а-я]*)|кто[\s\S]{0,40}купил|кто\s+это\s+поставил|кто\s+поставил|у\s+кого\s+купили|у\s+кого\s+куплено|где\s+мы\s+купили|где\s+куплено|по\s+каким\s+документам|какими\s+документами|покажи\s+документы|документы[\s\S]{0,80}(?:по\s+(?:ним|ней|нему|этой\s+позиции|этому\s+товару)|операци)|документы\s+закупки|buyer|sale\s+trace|supplier|vendor|purchase\s+documents|purchase[\s-]?to[\s-]?sale|old\s+purchase|aged\s+stock)/iu.test(value) || (0, inventoryLifecycleCueHelpers_1.hasInventoryProfitabilityCue)(value)); } function hasShortInventoryPurchaseFollowupCue(text) { return /(?:^|[\s,.;:!?])(а\s+)?(?:купили\s+у\s+кого|у\s+кого\s+купили|поставщик|продавец|seller)(?:[\s,.;:!?]|$)/iu.test(String(text ?? "")); } function isInventorySelectedObjectOrRootIntent(intent) { return (intent === "inventory_on_hand_as_of_date" || intent === "inventory_purchase_provenance_for_item" || intent === "inventory_purchase_documents_for_item" || intent === "inventory_sale_trace_for_item" || intent === "inventory_margin_ranking_for_nomenclature" || intent === "inventory_profitability_for_item" || intent === "inventory_purchase_to_sale_chain" || intent === "inventory_aging_by_purchase_date"); } function isGenericCanonicalDriftIntent(intent) { return (intent === "open_items_by_counterparty_or_contract" || intent === "customer_revenue_and_payments" || intent === "list_documents_by_counterparty" || intent === "list_documents_by_contract" || intent === "bank_operations_by_counterparty" || intent === "bank_operations_by_contract" || intent === "documents_forming_balance"); } function hasInventoryMarginRankingAccountCorrectionCue(text) { const value = String(text ?? "").toLowerCase(); if (!value.trim()) { return false; } return (/\b41(?:[.,]\d{1,2})?\b/iu.test(value) && /\b01(?:[.,]\d{1,2})?\b/iu.test(value) && /(?:\u0430\s+\u043d\u0435|\u043d\u0435|\u0432\u043c\u0435\u0441\u0442\u043e|not|instead)/iu.test(value)); } function hasSameDateFollowupSignal(text) { return /(?:эту\s+же\s+дат(?:у|е|ой)|ту\s+же\s+дат(?:у|е|ой)|same\s+date)/iu.test(String(text ?? "")); } function hasExplicitCurrentDateSignal(text) { return /(?:текущ(?:ую|ая|ий|ее|ей)\s+дат(?:у|а|е|ой)|сегодняшн(?:юю|ий|ей)\s+дат(?:у|а|е|ой)|today|current\s+date)/iu.test(String(text ?? "")); } function hasInventoryTemporalRootFollowupCue(text) { const value = String(text ?? "").trim().toLowerCase(); if (!value) { return false; } const tokenCount = value.split(/\s+/).filter(Boolean).length; const hasMonthYearCue = /(?:январ(?:ь|е)|феврал(?:ь|е)|март(?:е)?|апрел(?:ь|е)|ма(?:й|е)|июн(?:ь|е)|июл(?:ь|е)|август(?:е)?|сентябр(?:ь|е)|октябр(?:ь|е)|ноябр(?:ь|е)|декабр(?:ь|е))(?:\s+\d{4})?/iu.test(value) || /\b(?:19|20)\d{2}\b/u.test(value); if (tokenCount <= 3 && hasMonthYearCue) { return true; } const hasInventoryLexeme = /(?:остат|склад|товар|позици|номенклатур)/iu.test(value); return hasInventoryLexeme && (hasMonthYearCue || hasSameDateFollowupSignal(value)); } function shouldPreferRawFollowupMessage(userMessage, addressInputMessage, carryover, addressPreDecompose, toNonEmptyString) { if (!carryover?.followupContext || typeof carryover.followupContext !== "object") { return false; } const rawMessage = toNonEmptyString(userMessage); const canonicalMessage = toNonEmptyString(addressInputMessage); if (!rawMessage || !canonicalMessage || rawMessage === canonicalMessage) { return false; } const predecomposeContract = addressPreDecompose?.predecomposeContract && typeof addressPreDecompose.predecomposeContract === "object" ? addressPreDecompose.predecomposeContract : null; const mode = toNonEmptyString(predecomposeContract?.mode) ?? "unknown"; const intent = toNonEmptyString(predecomposeContract?.intent) ?? "unknown"; const followupContext = carryover.followupContext && typeof carryover.followupContext === "object" ? carryover.followupContext : null; 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 hasInventoryMarginRankingCarryover = previousIntent === "inventory_margin_ranking_for_nomenclature" || rootIntent === "inventory_margin_ranking_for_nomenclature"; const hasInventoryMarginRankingAccountCorrection = hasInventoryMarginRankingCarryover && [rawMessage, canonicalMessage].some((message) => hasInventoryMarginRankingAccountCorrectionCue(message)); 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; } if (hasInventoryFrameCarryover && hasInventoryTemporalRootFollowupCue(rawMessage) && (intent === "account_balance_snapshot" || intent === "documents_forming_balance" || intent === "unknown")) { return true; } if (hasInventoryMarginRankingAccountCorrection && (intent === "account_balance_snapshot" || intent === "documents_forming_balance" || intent === "unknown")) { return true; } return ((hasSelectedObjectInventorySignal(rawMessage) || hasInventoryItemCarryover) && (hasSelectedObjectInventoryActionCue(rawMessage) || hasShortInventoryPurchaseFollowupCue(rawMessage)) && (isGenericCanonicalDriftIntent(intent) || intent === "unknown")); } function fallbackAddressPreDecompose(userMessage, llmProvider, buildAddressLlmPredecomposeContractV1, sanitizeAddressMessageForFallback) { const provider = llmProvider === "local" ? "local" : llmProvider === "openai" ? "openai" : null; return { attempted: false, applied: false, provider, traceId: null, effectiveMessage: userMessage, reason: "disabled_by_feature_flag", llmCanonicalCandidateDetected: false, predecomposeContract: buildAddressLlmPredecomposeContractV1({ sourceMessage: userMessage, canonicalMessage: userMessage }), fallbackRuleHit: null, sanitizedUserMessage: sanitizeAddressMessageForFallback(userMessage), toolGateDecision: null, toolGateReason: null }; } async function buildAssistantAddressOrchestrationRuntime(input) { const initialAddressPreDecompose = input.featureAddressLlmPredecomposeV1 ? await input.runAddressLlmPreDecompose() : fallbackAddressPreDecompose(input.userMessage, input.llmProvider, input.buildAddressLlmPredecomposeContractV1, input.sanitizeAddressMessageForFallback); let addressPreDecompose = initialAddressPreDecompose; let addressInputMessage = input.toNonEmptyString(addressPreDecompose?.effectiveMessage) ?? input.userMessage; let carryover = input.resolveAddressFollowupCarryoverContext(input.userMessage, input.sessionItems, addressInputMessage, addressPreDecompose, input.sessionAddressNavigationState); if (shouldPreferRawFollowupMessage(input.userMessage, addressInputMessage, carryover, addressPreDecompose, input.toNonEmptyString)) { addressInputMessage = input.userMessage; addressPreDecompose = { ...addressPreDecompose, applied: false, effectiveMessage: input.userMessage, reason: "followup_raw_message_preferred_over_llm_rewrite", predecomposeContract: input.buildAddressLlmPredecomposeContractV1({ sourceMessage: input.userMessage, canonicalMessage: input.userMessage }) }; carryover = input.resolveAddressFollowupCarryoverContext(input.userMessage, input.sessionItems, addressInputMessage, addressPreDecompose, input.sessionAddressNavigationState); } const followupContext = toRecordObject(carryover?.followupContext); const routePolicyRuntime = (0, assistantRoutePolicyRuntimeAdapter_1.runAssistantRoutePolicyRuntime)({ rawUserMessage: input.userMessage, effectiveAddressUserMessage: addressInputMessage, followupContext, llmPreDecomposeMeta: addressPreDecompose, sessionItems: input.sessionItems, sessionOrganizationScope: input.sessionOrganizationScope ?? null, useMock: input.useMock, resolveAssistantOrchestrationDecision: input.resolveAssistantOrchestrationDecision }); const orchestrationDecision = routePolicyRuntime.orchestrationDecision; const orchestrationContract = toRecordObject(orchestrationDecision.orchestrationContract); const predecomposeContract = toRecordObject(addressPreDecompose.predecomposeContract); const explicitPredecomposeOrganization = predecomposeOrganizationName(predecomposeContract, input.toNonEmptyString); const discoveryFollowupContextWithOrganization = mergeOrganizationIntoDiscoveryFollowupContext(followupContext, explicitPredecomposeOrganization ? null : sessionOrganizationName(input.sessionOrganizationScope ?? null, input.toNonEmptyString)); const discoveryFollowupContext = mergeBusinessOverviewDateContextForCompactCashflow({ userMessage: input.userMessage, followupContext: discoveryFollowupContextWithOrganization, sessionItems: input.sessionItems, toNonEmptyString: input.toNonEmptyString }); const discoveryFollowupContextWithProofBundles = mergeBusinessOverviewProofBundlesFromSessionItems({ followupContext: discoveryFollowupContext, userMessage: input.userMessage, sessionItems: input.sessionItems, toNonEmptyString: input.toNonEmptyString }); const discoveryFollowupContextWithStateProofBundles = mergeBusinessOverviewProofBundlesFromNavigationState({ followupContext: discoveryFollowupContextWithProofBundles, sessionAddressNavigationState: input.sessionAddressNavigationState, predecomposeContract, userMessage: input.userMessage, toNonEmptyString: input.toNonEmptyString }); const dialogContinuationContract = input.buildAddressDialogContinuationContractV2(input.userMessage, addressInputMessage, carryover, addressPreDecompose); const runDiscoveryEntryPoint = input.runMcpDiscoveryRuntimeEntryPoint ?? assistantMcpDiscoveryRuntimeEntryPoint_1.runAssistantMcpDiscoveryRuntimeEntryPoint; let mcpDiscoveryRuntimeEntryPoint = null; let mcpDiscoveryRuntimeEntryPointError = null; try { mcpDiscoveryRuntimeEntryPoint = (await runDiscoveryEntryPoint({ userMessage: input.userMessage, effectiveMessage: addressInputMessage, assistantTurnMeaning: toRecordObject(orchestrationContract?.assistant_turn_meaning), predecomposeContract, followupContext: discoveryFollowupContextWithStateProofBundles, knownOrganizations: sessionKnownOrganizations(input.sessionOrganizationScope ?? null) })); } catch (error) { mcpDiscoveryRuntimeEntryPointError = String(error instanceof Error ? error.message : error ?? "unknown_error").slice(0, 280); } const addressRuntimeMeta = { ...addressPreDecompose, toolGateDecision: orchestrationDecision.toolGateDecision ?? null, toolGateReason: orchestrationDecision.toolGateReason ?? null, dialogContinuationContract, orchestrationContract: orchestrationContract ?? null, routePolicyContract: routePolicyRuntime.routePolicyContract, mcpDiscoveryRuntimeEntryPoint, mcpDiscoveryRuntimeEntryPointError }; return { addressPreDecompose, addressInputMessage, carryover, orchestrationDecision, addressRuntimeMeta, livingModeDecision: routePolicyRuntime.livingModeDecision }; }