"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.runAssistantAddressLaneResponseRuntime = runAssistantAddressLaneResponseRuntime; const assistantAddressTurnFinalizeRuntimeAdapter_1 = require("./assistantAddressTurnFinalizeRuntimeAdapter"); const assistantCapabilityBindingResponseGuard_1 = require("./assistantCapabilityBindingResponseGuard"); const assistantCapabilityRuntimeBindingAdapter_1 = require("./assistantCapabilityRuntimeBindingAdapter"); const assistantMcpDiscoveryDebugAttachment_1 = require("./assistantMcpDiscoveryDebugAttachment"); const assistantMcpDiscoveryResponsePolicy_1 = require("./assistantMcpDiscoveryResponsePolicy"); const assistantRuntimeContractResolver_1 = require("./assistantRuntimeContractResolver"); const assistantStateTransitionRuntimeAdapter_1 = require("./assistantStateTransitionRuntimeAdapter"); const assistantTruthAnswerPolicyRuntimeAdapter_1 = require("./assistantTruthAnswerPolicyRuntimeAdapter"); function toRecordObject(value) { if (!value || typeof value !== "object") { return null; } return value; } function toNullableString(value) { if (typeof value !== "string") { return null; } const trimmed = value.trim(); return trimmed.length > 0 ? trimmed : null; } function toNullableBoolean(value) { if (typeof value === "boolean") { return value; } return undefined; } function normalizeAddressReplyType(value) { return value === "factual" || value === "partial_coverage" ? value : "partial_coverage"; } function sameBusinessLabel(left, right) { const normalizedLeft = toNullableString(left)?.toLocaleLowerCase("ru-RU").replace(/ё/g, "е"); const normalizedRight = toNullableString(right)?.toLocaleLowerCase("ru-RU").replace(/ё/g, "е"); return Boolean(normalizedLeft && normalizedRight && (normalizedLeft === normalizedRight || normalizedLeft.includes(normalizedRight) || normalizedRight.includes(normalizedLeft))); } function firstString(values) { for (const value of values) { const text = toNullableString(value); if (text) { return text; } } return null; } function legalOrganizationLabelFromClarification(value) { const text = toNullableString(value); if (!text) { return null; } const compact = text.replace(/\s+/gu, " ").replace(/[.!?]+$/u, "").trim(); if (compact.length > 120 || !/^(?:ООО|ПАО|АО|ИП)\s+\S/iu.test(compact)) { return null; } return compact; } function cleanComparisonScopeCompanyLine(line, organization) { let clean = String(line ?? "") .replace(/\bcompany-level\b/giu, "общий по компании") .replace(/\breusable bundle\b/giu, "сохраненный подтвержденный срез"); if (organization) { clean = clean.replace(/по компании\s+Альтернатива Плюс/iu, `по компании ${organization}`); } return clean.trim(); } function hasComparisonScopeProofCue(value) { const text = toNullableString(value)?.toLocaleLowerCase("ru-RU").replace(/\s+/gu, " ").trim(); if (!text) { 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(text); } function buildComparisonScopeProofReply(input) { if (!hasComparisonScopeProofCue(input.userMessage)) { return null; } const entryPoint = toRecordObject(input.debug.assistant_mcp_discovery_entry_point_v1); const turnInput = toRecordObject(entryPoint?.turn_input); const turnMeaning = toRecordObject(turnInput?.turn_meaning_ref); const isBusinessOverview = toNullableString(turnMeaning?.asked_domain_family) === "business_overview"; if (!isBusinessOverview) { return null; } const separateCandidates = Array.isArray(turnMeaning?.business_overview_separate_entity_candidates) ? turnMeaning.business_overview_separate_entity_candidates : []; const separateSubject = firstString([...separateCandidates, turnMeaning?.metadata_scope_hint]); if (!separateSubject) { return null; } const sessionRecord = toRecordObject(input.session); const addressNavigationState = toRecordObject(sessionRecord?.address_navigation_state); const sessionContext = toRecordObject(addressNavigationState?.session_context); const comparisonScope = toRecordObject(sessionContext?.comparison_scope); const comparisonCounterparty = toRecordObject(comparisonScope?.counterparty); const proofBundles = toRecordObject(comparisonScope?.proof_bundles); const valueBundle = toRecordObject(proofBundles?.counterparty_value_flow_bundle); const documentBundle = toRecordObject(proofBundles?.counterparty_document_bundle); if (!valueBundle || !sameBusinessLabel(separateSubject, valueBundle.counterparty ?? comparisonCounterparty?.label)) { return null; } const incoming = toRecordObject(valueBundle.incoming_customer_revenue); const outgoing = toRecordObject(valueBundle.outgoing_supplier_payout); const incomingAmount = toNullableString(incoming?.total_amount_human_ru); const outgoingAmount = toNullableString(outgoing?.total_amount_human_ru); const netAmount = toNullableString(valueBundle.net_amount_human_ru); if (!incomingAmount && !outgoingAmount && !netAmount) { return null; } const organization = legalOrganizationLabelFromClarification(input.userMessage) ?? toNullableString(turnMeaning?.explicit_organization_scope) ?? toNullableString(toRecordObject(comparisonScope?.organization)?.label); const documentCount = Number(toRecordObject(documentBundle)?.document_count); const documentText = Number.isFinite(documentCount) && documentCount > 0 ? `, документы: ${documentCount}` : ""; const lines = String(input.baseReply ?? "") .split(/\r?\n/u) .map((line) => line.trim()) .filter(Boolean); const companyLine = cleanComparisonScopeCompanyLine(lines[0] ?? `Коротко: по компании ${organization ?? "выбранной организации"} подтвержден общий денежный срез.`, organization); const netDirection = valueBundle.net_direction === "net_outgoing" ? "нетто в минус" : "нетто в нашу сторону"; const counterparty = toNullableString(valueBundle.counterparty) ?? separateSubject; return { reply: [ `${companyLine}; отдельно по ${counterparty}: получили ${incomingAmount ?? "0 руб."}, заплатили ${outgoingAmount ?? "0 руб."}, ${netDirection} ${netAmount ?? "0 руб."}${documentText}.`, `Отдельно по контрагенту ${counterparty}: это ранее подтвержденный контрагентский срез, а не перенос общих сумм компании на контрагента.`, `Нельзя утверждать: чистую прибыль, полноценный финрезультат, юридические роли клиентов/поставщиков и выводы по ${counterparty} из общих сумм компании без отдельного контрагентского среза.` ].join("\n"), audit: { applied: true, source: "address_navigation_state.comparison_scope.proof_bundles", counterparty, organization: organization ?? null, document_count: Number.isFinite(documentCount) && documentCount > 0 ? documentCount : null } }; } function buildAppliedMcpDiscoveryRoutePatch(debug, applied) { if (!applied) { return {}; } const selectedChain = toNullableString(debug.mcp_discovery_selected_chain_id); if (selectedChain === "business_overview") { return { detected_intent: "business_overview", detected_intent_confidence: "high", selected_recipe: "business_overview", response_type: "LIMITED_WITH_REASON", mcp_discovery_effective_response_route: "business_overview" }; } return {}; } function normalizeAddressLaneDebug(value) { return (toRecordObject(value) ?? {}); } function normalizeCarryoverMeta(value) { const source = toRecordObject(value); if (!source) { return null; } const followupContext = toRecordObject(source.followupContext); const previousAddressIntent = toNullableString(source.previousAddressIntent) ?? toNullableString(followupContext?.previous_intent); const previousAddressAnchor = toNullableString(source.previousAddressAnchor) ?? toNullableString(followupContext?.previous_anchor); if (!previousAddressIntent && !previousAddressAnchor) { return null; } return { previousAddressIntent, previousAddressAnchor }; } function normalizeLlmPreDecomposeMeta(value) { const source = toRecordObject(value); if (!source) { return null; } const dialogContinuationContractRaw = toRecordObject(source.dialogContinuationContract); const addressRetryAuditRaw = toRecordObject(source.addressRetryAudit); const predecomposeContractRaw = toRecordObject(source.predecomposeContract); const predecomposePeriodRaw = toRecordObject(predecomposeContractRaw?.period); const semanticExtractionContractRaw = toRecordObject(source.semanticExtractionContract); const normalized = {}; const attempted = toNullableBoolean(source.attempted); if (attempted !== undefined) normalized.attempted = attempted; const applied = toNullableBoolean(source.applied); if (applied !== undefined) normalized.applied = applied; const provider = toNullableString(source.provider); if (provider) normalized.provider = provider; const traceId = toNullableString(source.traceId); if (traceId) normalized.traceId = traceId; const reason = toNullableString(source.reason); if (reason) normalized.reason = reason; const fallbackRuleHit = toNullableString(source.fallbackRuleHit); if (fallbackRuleHit) normalized.fallbackRuleHit = fallbackRuleHit; const sanitizedUserMessage = toNullableString(source.sanitizedUserMessage); if (sanitizedUserMessage) normalized.sanitizedUserMessage = sanitizedUserMessage; const toolGateDecision = toNullableString(source.toolGateDecision); if (toolGateDecision) normalized.toolGateDecision = toolGateDecision; const toolGateReason = toNullableString(source.toolGateReason); if (toolGateReason) normalized.toolGateReason = toolGateReason; if (dialogContinuationContractRaw) { const decision = toNullableString(dialogContinuationContractRaw.decision); const targetIntent = toNullableString(dialogContinuationContractRaw.target_intent); if (decision || targetIntent) { normalized.dialogContinuationContract = { decision, target_intent: targetIntent }; } } if (addressRetryAuditRaw) { const retryAttempted = toNullableBoolean(addressRetryAuditRaw.attempted); const retryReason = toNullableString(addressRetryAuditRaw.reason); const initialLimitedCategory = toNullableString(addressRetryAuditRaw.initial_limited_category); const retryResultCategory = toNullableString(addressRetryAuditRaw.retry_result_category); if (retryAttempted !== undefined || retryReason || initialLimitedCategory || retryResultCategory) { normalized.addressRetryAudit = { attempted: retryAttempted, reason: retryReason, initial_limited_category: initialLimitedCategory, retry_result_category: retryResultCategory }; } } if (predecomposeContractRaw) { const intent = toNullableString(predecomposeContractRaw.intent); const aggregationProfile = toNullableString(predecomposeContractRaw.aggregation_profile); const periodScope = toNullableString(predecomposePeriodRaw?.scope); if (intent || aggregationProfile || periodScope) { normalized.predecomposeContract = { intent, aggregation_profile: aggregationProfile, period: periodScope ? { scope: periodScope } : null }; } } if (semanticExtractionContractRaw) { const valid = toNullableBoolean(semanticExtractionContractRaw.valid); const quality = toNullableString(semanticExtractionContractRaw.quality); const applyCanonicalRecommended = toNullableBoolean(semanticExtractionContractRaw.apply_canonical_recommended); const reasonCodes = Array.isArray(semanticExtractionContractRaw.reason_codes) ? semanticExtractionContractRaw.reason_codes .map((item) => toNullableString(item)) .filter((item) => Boolean(item)) : []; if (valid !== undefined || quality || applyCanonicalRecommended !== undefined || reasonCodes.length > 0) { normalized.semanticExtractionContract = { valid: valid ?? null, quality, apply_canonical_recommended: applyCanonicalRecommended ?? null, reason_codes: reasonCodes }; } } const hasUsefulField = Object.values(normalized).some((item) => item !== undefined && item !== null); return hasUsefulField ? normalized : null; } function runAssistantAddressLaneResponseRuntime(input) { const finalizeAddressTurnSafe = input.finalizeAddressTurn ?? assistantAddressTurnFinalizeRuntimeAdapter_1.finalizeAssistantAddressTurn; const safeAddressReply = input.sanitizeOutgoingAssistantText(input.addressLane.reply_text); const debug = input.buildAddressDebugPayload(input.addressLane.debug, input.llmPreDecomposeMeta); const followupOffer = input.buildAddressFollowupOffer(debug); if (followupOffer) { debug.address_followup_offer = followupOffer; } const laneOrganizationCandidates = Array.isArray(input.addressLane.debug?.organization_candidates) ? input.addressLane.debug.organization_candidates : []; const debugKnownOrganizations = input.mergeKnownOrganizations([ ...input.knownOrganizations, ...laneOrganizationCandidates ]); const debugFilters = debug?.extracted_filters && typeof debug.extracted_filters === "object" ? debug.extracted_filters : null; const debugActiveOrganization = input.toNonEmptyString(debugFilters?.organization) ?? input.toNonEmptyString(input.activeOrganization); const followupContextSource = input.carryoverMeta?.followupContext && typeof input.carryoverMeta.followupContext === "object" ? input.carryoverMeta.followupContext : null; if (debugKnownOrganizations.length > 0) { debug.assistant_known_organizations = debugKnownOrganizations; } if (debugActiveOrganization) { debug.assistant_active_organization = debugActiveOrganization; } const rootIntent = input.toNonEmptyString(followupContextSource?.root_intent); const currentFrameKind = input.toNonEmptyString(followupContextSource?.current_frame_kind); const rootFilters = followupContextSource?.root_filters && typeof followupContextSource.root_filters === "object" ? followupContextSource.root_filters : null; if (rootIntent || currentFrameKind) { debug.address_root_frame_context = { root_intent: rootIntent, current_frame_kind: currentFrameKind, organization: input.toNonEmptyString(rootFilters?.organization), as_of_date: input.toNonEmptyString(rootFilters?.as_of_date), period_from: input.toNonEmptyString(rootFilters?.period_from), period_to: input.toNonEmptyString(rootFilters?.period_to) }; } const debugWithRuntimeContracts = (0, assistantRuntimeContractResolver_1.attachAssistantRuntimeContractShadow)(debug, { userMessage: input.userMessage, addressRuntimeMeta: input.llmPreDecomposeMeta }); const debugWithTruthAnswerPolicy = (0, assistantTruthAnswerPolicyRuntimeAdapter_1.attachAssistantTruthAnswerPolicy)(debugWithRuntimeContracts, { addressRuntimeMeta: input.llmPreDecomposeMeta, replyType: normalizeAddressReplyType(input.addressLane.reply_type) }); const debugWithStateTransition = (0, assistantStateTransitionRuntimeAdapter_1.attachAssistantStateTransition)(debugWithTruthAnswerPolicy, { addressRuntimeMeta: input.llmPreDecomposeMeta, replyType: normalizeAddressReplyType(input.addressLane.reply_type) }); const debugWithCapabilityBinding = (0, assistantCapabilityRuntimeBindingAdapter_1.attachAssistantCapabilityRuntimeBinding)(debugWithStateTransition, { addressRuntimeMeta: input.llmPreDecomposeMeta, replyType: normalizeAddressReplyType(input.addressLane.reply_type) }); const debugWithMcpDiscovery = (0, assistantMcpDiscoveryDebugAttachment_1.attachAssistantMcpDiscoveryDebug)(debugWithCapabilityBinding, { addressRuntimeMeta: input.llmPreDecomposeMeta }); const guardedResponse = (0, assistantCapabilityBindingResponseGuard_1.applyAssistantCapabilityBindingResponseGuard)({ assistantReply: safeAddressReply, replyType: normalizeAddressReplyType(input.addressLane.reply_type), capabilityBinding: debugWithMcpDiscovery.assistant_capability_binding_v1 }); const debugWithResponseGuard = { ...debugWithMcpDiscovery, capability_binding_response_guard: guardedResponse.audit }; const mcpDiscoveryResponsePolicy = (0, assistantMcpDiscoveryResponsePolicy_1.applyAssistantMcpDiscoveryResponsePolicy)({ currentReply: guardedResponse.assistantReply, currentReplySource: "address_query_runtime_v1", currentReplyType: guardedResponse.replyType, addressRuntimeMeta: debugWithResponseGuard }); const finalAssistantReply = mcpDiscoveryResponsePolicy.applied ? mcpDiscoveryResponsePolicy.reply_text : guardedResponse.assistantReply; const comparisonScopeProofReply = buildComparisonScopeProofReply({ baseReply: finalAssistantReply, debug: debugWithResponseGuard, session: input.getSession(input.sessionId), userMessage: input.userMessage }); const finalAssistantReplyWithComparisonProof = comparisonScopeProofReply?.reply ?? finalAssistantReply; const finalReplyType = mcpDiscoveryResponsePolicy.applied ? "partial_coverage" : guardedResponse.replyType; const finalDebug = { ...debugWithResponseGuard, mcp_discovery_response_policy_v1: mcpDiscoveryResponsePolicy, mcp_discovery_response_candidate_v1: mcpDiscoveryResponsePolicy.candidate, mcp_discovery_response_applied: mcpDiscoveryResponsePolicy.applied, comparison_scope_response_augmentation_v1: comparisonScopeProofReply?.audit ?? null, ...buildAppliedMcpDiscoveryRoutePatch(debugWithResponseGuard, mcpDiscoveryResponsePolicy.applied) }; const finalization = finalizeAddressTurnSafe({ sessionId: input.sessionId, userMessage: input.userMessage, effectiveAddressUserMessage: input.effectiveAddressUserMessage, assistantReply: finalAssistantReplyWithComparisonProof, replyType: finalReplyType, addressLaneDebug: normalizeAddressLaneDebug(input.addressLane.debug), debug: finalDebug, carryoverMeta: normalizeCarryoverMeta(input.carryoverMeta), llmPreDecomposeMeta: normalizeLlmPreDecomposeMeta(input.llmPreDecomposeMeta), appendItem: input.appendItem, getSession: input.getSession, persistSession: input.persistSession, cloneConversation: input.cloneConversation, logEvent: input.logEvent, messageIdFactory: input.messageIdFactory }); return { response: finalization.response, debug: finalDebug }; }