"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createAssistantBoundaryPolicy = createAssistantBoundaryPolicy; function normalizeSelectedOrganization(value, normalizeOrganizationScopeValue) { return normalizeOrganizationScopeValue(value) ?? String(value ?? "").trim(); } function containsCjkChars(text) { const source = String(text ?? ""); if (!source) { return false; } return /[\u3400-\u9FFF\uF900-\uFAFF]/u.test(source); } function containsLetterLikeChars(text) { const source = String(text ?? ""); if (!source) { return false; } return /[A-Za-z\u0400-\u04FF]/u.test(source); } function createAssistantBoundaryPolicy(deps) { function buildAssistantDataScopeContractReply(scopeProbe = null) { const organizations = Array.isArray(scopeProbe?.organizations) ? scopeProbe.organizations .map((item) => normalizeSelectedOrganization(item, deps.normalizeOrganizationScopeValue)) .filter((item) => item.length > 0) .filter((item, index, array) => array.indexOf(item) === index) : []; if (organizations.length === 1) { return [ `Сейчас доступна организация: ${organizations[0]}.`, "Могу сразу показать по ней документы, операции, договоры или остатки." ].join(" "); } if (organizations.length > 1) { const preview = organizations.slice(0, 10).join(", "); return [ `Сейчас доступны организации (${organizations.length}): ${preview}.`, "Скажите, по какой организации смотреть данные." ].join(" "); } if (scopeProbe?.status === "unresolved_with_error" && scopeProbe?.error) { return [ "Сейчас не удалось определить список организаций из подключенной базы.", `Техническая причина: ${scopeProbe.error}.`, "Проверьте подключение, и я сразу назову доступный контур." ].join(" "); } return [ "Сейчас вижу только данные текущего подключенного контура.", "Если в нем несколько организаций, скажите, по какой смотреть данные." ].join(" "); } function buildAssistantProactiveOrganizationOfferReply(scopeProbe = null) { const organizations = Array.isArray(scopeProbe?.organizations) ? scopeProbe.organizations .map((item) => normalizeSelectedOrganization(item, deps.normalizeOrganizationScopeValue)) .filter((item) => item.length > 0) .filter((item, index, array) => array.indexOf(item) === index) : []; if (organizations.length === 1) { return [ `Если дальше пойдём в данные 1С, могу сразу держать в контуре ${organizations[0]}.`, "Можно просто писать вопрос по документам, остаткам, НДС или контрагентам." ].join(" "); } if (organizations.length > 1) { const preview = organizations.slice(0, 10).join(", "); return [ `Если дальше пойдём в данные 1С, могу сразу зафиксировать организацию: ${preview}.`, "Просто напишите название компании, и дальше буду держать её активной в этой сессии." ].join(" "); } return ""; } function buildAssistantDataScopeSelectionReply(organization) { const selected = normalizeSelectedOrganization(organization, deps.normalizeOrganizationScopeValue); return [ `Отлично, фиксирую рабочую организацию: ${selected}.`, "Дальше буду держать этот контур как активный, пока вы не переключите организацию." ].join(" "); } function buildAssistantOrganizationFactBoundaryReply(organization) { const selected = normalizeSelectedOrganization(organization, deps.normalizeOrganizationScopeValue); if (selected) { return [ `По организации ${selected} не буду называть дату/возраст без live-подтвержденного источника.`, "Если нужно, запрошу факт из 1С и верну только подтвержденный ответ." ].join(" "); } return [ "Не буду называть дату/возраст организации без live-подтвержденного источника.", "Сначала получу факт из 1С, потом дам точный ответ." ].join(" "); } function buildAssistantOperationalBoundaryReply() { return [ "Понимаю, что ситуация срочная.", "Я не могу сам настраивать 1С или менять базу/конфигурацию.", "Могу помочь безопасно: разберем симптомы и подготовим точные шаги для вашего 1С/ИТ-админа." ].join(" "); } function buildAssistantSafetyRefusalReply() { return [ "Я не могу помогать с удалением базы или скрытием данных.", "Если вам угрожает опасность, срочно звоните 112 и следуйте указаниям экстренных служб.", "По 1С могу дать только безопасные диагностические рекомендации." ].join(" "); } function applyLivingChatScriptGuard(chatText, userMessage) { const source = String(chatText ?? "").trim(); if (!source) { return { text: "", applied: false, reason: null }; } if (!containsCjkChars(source) || containsCjkChars(userMessage)) { return { text: source, applied: false, reason: null }; } const stripped = source .replace(/[\u3400-\u9FFF\uF900-\uFAFF]+/gu, "") .replace(/[,。、!?;:()【】]/gu, "") .replace(/\s{2,}/g, " ") .replace(/\s+([,.!?;:])/g, "$1") .trim(); if (stripped && containsLetterLikeChars(stripped)) { return { text: stripped, applied: true, reason: "unexpected_cjk_fragment_stripped" }; } return { text: "Понял. Сформулируйте, что именно нужно по данным 1С, и я помогу по шагам.", applied: true, reason: "unexpected_cjk_fragment_fallback" }; } function applyLivingChatGroundingGuard(input) { const userMessage = String(input?.userMessage ?? ""); const chatText = String(input?.chatText ?? "").trim(); const organization = deps.toNonEmptyString(input?.organization); if (!chatText) { return { text: chatText, applied: false, reason: null }; } if (!deps.hasOrganizationFactLookupSignal(userMessage)) { return { text: chatText, applied: false, reason: null }; } if (/(?:не\s+могу|не\s+вижу|после\s+проверки|live|подтвержден)/i.test(chatText)) { return { text: chatText, applied: false, reason: null }; } const hasSpecificUnverifiedFact = /(?:\b\d{1,2}[./-]\d{1,2}[./-](?:\d{2}|\d{4})\b|\b(?:19|20)\d{2}\b|\b\d+\s+лет\b)/i.test(chatText); if (!hasSpecificUnverifiedFact) { return { text: chatText, applied: false, reason: null }; } return { text: buildAssistantOrganizationFactBoundaryReply(organization), applied: true, reason: "organization_fact_without_live_source_blocked" }; } return { buildAssistantDataScopeContractReply, buildAssistantProactiveOrganizationOfferReply, buildAssistantDataScopeSelectionReply, buildAssistantOrganizationFactBoundaryReply, buildAssistantOperationalBoundaryReply, buildAssistantSafetyRefusalReply, applyLivingChatScriptGuard, applyLivingChatGroundingGuard }; }