ДОМЕНЫ - ВОПРОСЫ - Исправить обработку коротких debt follow-up и защиту от диагностических LLM rewrite

This commit is contained in:
2026-04-12 22:34:59 +03:00
parent 040a55aaea
commit 98872c2f11
35 changed files with 1745 additions and 195 deletions
@@ -1990,7 +1990,7 @@ function textMojibakeScoreForAddress(value) {
const source = String(value ?? "");
const cyrillic = (source.match(/[А-Яа-яЁё]/g) ?? []).length;
const latin = (source.match(/[A-Za-z]/g) ?? []).length;
const hardMarkers = (source.match(/[Ѓѓ‚„…†‡€‰‹ЉЊЌЋЏ‘’“”•–—™љ›њќћџ]/g) ?? []).length;
const hardMarkers = (source.match(/[Ѓѓ‚„…†‡€‰‹ЉЊЌЋЏ�?’“”•–—™љ›њќћџ]/g) ?? []).length;
const pairMarkers = (source.match(/(?:Р.|С.|Ð.|Ñ.)/g) ?? []).length;
const doubleEncodedMarkers = (source.match(/(?:Г[Ђ-џ]|В[Ђ-џ]|Ã.|Â.)/gu) ?? []).length;
return cyrillic + latin - hardMarkers * 3 - pairMarkers * 2 - doubleEncodedMarkers * 2;
@@ -2000,7 +2000,7 @@ function looksLikeMojibakeForAddress(value) {
if (!source.trim()) {
return false;
}
if (/[Ѓѓ‚„…†‡€‰‹ЉЊЌЋЏ‘’“”•–—™љ›њќћџ]/.test(source)) {
if (/[Ѓѓ‚„…†‡€‰‹ЉЊЌЋЏ�?’“”•–—™љ›њќћџ]/.test(source)) {
return true;
}
if ((source.match(/(?:Р.|С.|Ð.|Ñ.)/g) ?? []).length >= 2) {
@@ -2205,7 +2205,7 @@ function normalizeCounterpartyForFollowupMatch(value) {
return compactWhitespace(repairAddressMojibake(String(value ?? ""))
.toLowerCase()
.replace(/ё/g, "е")
.replace(/[«»"'`“”„’‘]/g, " ")
.replace(/[«»"'`“”„’�?]/g, " ")
.replace(/[^a-zа-я0-9\s._-]+/giu, " "));
}
function normalizeCounterpartyTokenForFollowupMatch(value) {
@@ -2251,7 +2251,7 @@ function extractDisplayedAddressEntityCandidates(replyText, entityType = "unknow
if (parts.length >= 2 && /^\d{4}-\d{2}-\d{2}/.test(parts[0] ?? "")) {
counterpartyCandidate = parts[1] ?? counterpartyCandidate;
}
const cleanedCandidate = compactWhitespace(counterpartyCandidate.replace(/^["'«»“”„`’‘]+|["'«»“”„`’‘]+$/gu, ""));
const cleanedCandidate = compactWhitespace(counterpartyCandidate.replace(/^["'«»“”„`’�?]+|["'«»“”„`’�?]+$/gu, ""));
if (!cleanedCandidate || cleanedCandidate.length < 2) {
continue;
}
@@ -2515,61 +2515,133 @@ function isImplicitAddressContinuationByLlm(userMessage, llmPreDecomposeMeta) {
return tokenCount > 0 && tokenCount <= 4;
}
function hasAddressFollowupContextSignal(userMessage) {
const rawText = compactWhitespace(String(userMessage ?? "").toLowerCase());
const repaired = repairAddressMojibake(String(userMessage ?? ""));
const text = compactWhitespace(repaired.toLowerCase());
if (!text) {
const repairedText = compactWhitespace(repaired.toLowerCase());
const samples = [rawText, repairedText].filter((item) => item.length > 0);
if (samples.length === 0) {
return false;
}
if (hasStandaloneAddressTopicSignal(text)) {
const hasAny = (pattern) => samples.some((sample) => pattern.test(sample));
const hasMarker = () => samples.some((sample) => hasFollowupMarker(sample));
const hasPointer = () => samples.some((sample) => hasReferentialPointer(sample));
const minTokens = samples.reduce((min, sample) => Math.min(min, countTokens(sample)), Number.POSITIVE_INFINITY);
const shortFollowup = minTokens <= 8;
const ultraShortFollowup = minTokens <= 3;
const debtRoleSwapToReceivables = shortFollowup &&
(/^(?:\u0430|a|\u0438|i)\s+(?:\u043d\u0430\u043c\s+)?\u043a\u0442\u043e(?=$|[\s,.;:!?])/iu.test(rawText) ||
/^(?:р°|a|рё|i)\s+(?:рЅр°рј\s+)?рєс‚рѕ(?=$|[\s,.;:!?])/iu.test(rawText));
if (debtRoleSwapToReceivables) {
return true;
}
const debtRoleSwapToPayables = shortFollowup &&
(/^(?:\u0430|a|\u0438|i)\s+(?:\u043c\u044b\s+)?\u043a\u043e\u043c\u0443(?=$|[\s,.;:!?])/iu.test(rawText) ||
/^(?:р°|a|рё|i)\s+(?:рјс‹\s+)?рєрѕрјсѓ(?=$|[\s,.;:!?])/iu.test(rawText));
if (debtRoleSwapToPayables) {
return true;
}
const shortContinuationCue = ultraShortFollowup &&
(/^(?:\u0434\u0430\u0432\u0430\u0439|\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0439|\u043f\u043e\u043a\u0430\u0437\u044b\u0432\u044b\u0430\u0439|\u0435\u0449[\u0435\u0451]|also|again|go|ok|okay)(?=$|[\s,.;:!?])/iu.test(rawText) ||
/^(?:рґр°рір°р№|рїрѕрєр°р·с‹рір°р№|рїрѕрєр°р·с‹ріс‹р°р№|рµс‰[рµс‘]|also|again|go|ok|okay)(?=$|[\s,.;:!?])/iu.test(rawText));
if (shortContinuationCue) {
return true;
}
const shortVatCue = ultraShortFollowup &&
/^(?:(?:\u0430|\u0438)\s+)?(?:(?:\u043f\u043e|po)\s+)?(?:\u043d\u0434\u0441|vat)(?=$|[\s,.;:!?])/iu.test(rawText);
if (shortVatCue) {
return true;
}
if (shortFollowup && hasAny(/^(?:а|a|и|i)\s+(?:нам\s+)?кто(?=$|[\s,.;:!?])/iu)) {
return true;
}
if (shortFollowup && hasAny(/^(?:а|a|и|i)\s+(?:мы\s+)?кому(?=$|[\s,.;:!?])/iu)) {
return true;
}
if (ultraShortFollowup && hasAny(/^(?:давай|показывай|показывыай|ещ[её]|also|again|go|ok|okay)(?=$|[\s,.;:!?])/iu)) {
return true;
}
if (hasStandaloneAddressTopicSignal(rawText || repairedText)) {
return false;
}
if (shouldHandleAsAssistantCapabilityMetaQuery(text)) {
if (shouldHandleAsAssistantCapabilityMetaQuery(rawText || repairedText)) {
return false;
}
if (/(?:за\s+вс[её]\s+время|за\s+весь\s+период|за\s+всю\s+истори(?:ю|и)|за\s+любой\s+период|for\s+all\s+time|all\s+time|for\s+entire\s+period|entire\s+period|for\s+any\s+period|any\s+period)/iu.test(text)) {
if (hasAny(/(?:за\s+вс[её]\s+время|за\s+весь\s+период|за\s+всю\s+истори(?:ю|и)|за\s+любой\s+период|for\s+all\s+time|all\s+time|for\s+entire\s+period|entire\s+period|for\s+any\s+period|any\s+period)/iu)) {
return true;
}
if (hasReferentialPointer(text)) {
if (hasPointer()) {
return true;
}
if (/(?:на\s+ту\s+же\s+дат[ауеы]|на\s+эту\s+же\s+дат[ауеы]|same\s+date|the\s+same\s+date|as\s+of\s+same\s+date)/iu.test(text)) {
if (hasAny(/(?:на\s+ту\s+же\s+дат[ауеы]|на\s+эту\s+же\s+дат[ауеы]|same\s+date|the\s+same\s+date|as\s+of\s+same\s+date)/iu)) {
return true;
}
const shortFollowup = countTokens(text) <= 8;
if (/(?:кроме|помимо)\s+(?:этого|этой|этот|эту|этих|этого\s+документа|этого\s+договора|этого\s+контрагента)/iu.test(text)) {
if (hasAny(/(?:кроме|помимо)\s+(?:этого|этой|этот|эту|этих|этого\s+документа|этого\s+договора|этого\s+контрагента)/iu)) {
return true;
}
if (/(?:есть\s+ещ[её]|что\s+ещ[её]|ещ[её]\s+что|ещ[её]\s+что-?то|остал(?:ось|ось\?)|друг(?:ое|ие))/iu.test(text) && countTokens(text) <= 12) {
if (hasAny(/(?:есть\s+ещ[её]|что\s+ещ[её]|ещ[её]\s+что|ещ[её]\s+что-?то|остал(?:ось|ось\?)|друг(?:ое|ие))/iu) && minTokens <= 12) {
return true;
}
if (shortFollowup && hasFollowupMarker(text)) {
if (shortFollowup && hasMarker()) {
return true;
}
if (shortFollowup && /(?:^|\s)(?:также|тоже|also|same|again|ещ[её]|теперь|then|now)(?=$|[\s,.;:!?])/iu.test(text)) {
if (shortFollowup && hasAny(/(?:^|\s)(?:также|тоже|also|same|again|ещ[её]|теперь|then|now)(?=$|[\s,.;:!?])/iu)) {
return true;
}
if (shortFollowup && hasAny(/(?:кто\s+из\s+(?:них|этих|тех)|кто\s+нов(?:ые|ых|ый)|кто\s+потом\s+исчез|кто\s+был\s+(?:только|ровно)\s+один\s+раз)/iu)) {
return true;
}
if (shortFollowup &&
/(?:кто\s+из\s+(?:них|этих|тех)|кто\s+нов(?:ые|ых|ый)|кто\s+потом\s+исчез|кто\s+был\s+(?:только|ровно)\s+один\s+раз)/iu.test(text)) {
return true;
}
if (shortFollowup && /^(?:а|и)\s+кто\b/iu.test(text)) {
hasAny(/(?:почему|why|из[-\s]?за\s+чего|как\s+так|reason)/iu) &&
hasAny(/(?:ндс|vat|прогноз|к\s+уплате|нул|ноль|\b0(?:[.,]0+)?\b)/iu)) {
return true;
}
if (shortFollowup &&
/(?:почему|why|из[-\s]?за\s+чего|как\s+так|reason)/iu.test(text) &&
/(?:ндс|vat|прогноз|к\s+уплате|нул|ноль|\b0(?:[.,]0+)?\b)/iu.test(text)) {
hasAny(/(?:^|\s)по\s+[a-zа-яё][a-zа-яё0-9._-]{1,}(?=$|[\s,.;:!?])/iu) &&
!hasAny(/(?:по\s+этому|по\s+тому|по\s+нему|по\s+ней|по\s+ним)/iu)) {
return true;
}
if (shortFollowup &&
/(?:^|\s)по\s+[a-zа-яё][a-zа-яё0-9._-]{1,}(?=$|[\s,.;:!?])/iu.test(text) &&
!/(?:по\s+этому|по\s+тому|по\s+нему|по\s+ней|по\s+ним)/iu.test(text)) {
return true;
}
if (shortFollowup && hasPeriodLiteral(text)) {
if (shortFollowup && samples.some((sample) => hasPeriodLiteral(sample))) {
return true;
}
return false;
}
function hasShortDebtMirrorFollowupSignal(userMessage) {
const rawText = compactWhitespace(String(userMessage ?? "").toLowerCase());
const repairedText = compactWhitespace(repairAddressMojibake(String(userMessage ?? "")).toLowerCase());
const samples = [rawText, repairedText].filter((item) => item.length > 0);
if (samples.length === 0) {
return false;
}
const minTokens = samples.reduce((min, sample) => Math.min(min, countTokens(sample)), Number.POSITIVE_INFINITY);
if (minTokens > 8) {
return false;
}
return samples.some((sample) => /^(?:а|a|и|i)\s+(?:нам\s+)?кто(?=$|[\s,.;:!?])/iu.test(sample) ||
/^(?:а|a|и|i)\s+(?:мы\s+)?кому(?=$|[\s,.;:!?])/iu.test(sample) ||
/^(?:р°|a|рё|i)\s+(?:рЅр°рј\s+)?рєс‚рѕ(?=$|[\s,.;:!?])/iu.test(sample) ||
/^(?:р°|a|рё|i)\s+(?:рјс‹\s+)?рєрѕрјсѓ(?=$|[\s,.;:!?])/iu.test(sample));
}
function resolveDebtRoleSwapFollowupIntent(userMessage, previousIntent) {
const normalized = compactWhitespace(String(userMessage ?? "").toLowerCase());
if (!normalized || countTokens(normalized) > 10) {
return null;
}
const hasReceivablesCue = /(?:нам\s+кто\s+долж|кто\s+нам\s+долж|кто\s+долж[а-яё]*\s+нам|дебитор|к\s+получению|к\s+взысканию|receivable)/iu.test(normalized) ||
/^(?:а|a|и|i)\s+(?:нам\s+)?кто(?=$|[\s,.;:!?])/iu.test(normalized) ||
/^(?:р°|a|рё|i)\s+(?:рЅр°рј\s+)?рєс‚рѕ(?=$|[\s,.;:!?])/iu.test(normalized);
const hasPayablesCue = /(?:мы\s+кому\s+долж|кому\s+мы\s+долж|кому\s+долж[а-яё]*\s+мы|кредитор|к\s+уплате|payable)/iu.test(normalized) ||
/^(?:а|a|и|i)\s+(?:мы\s+)?кому(?=$|[\s,.;:!?])/iu.test(normalized) ||
/^(?:р°|a|рё|i)\s+(?:рјс‹\s+)?рєрѕрјсѓ(?=$|[\s,.;:!?])/iu.test(normalized);
if ((previousIntent === "payables_confirmed_as_of_date" || previousIntent === "list_payables_counterparties") &&
hasReceivablesCue) {
return "receivables_confirmed_as_of_date";
}
if ((previousIntent === "receivables_confirmed_as_of_date" || previousIntent === "list_receivables_counterparties") &&
hasPayablesCue) {
return "payables_confirmed_as_of_date";
}
return null;
}
function resolveAddressFollowupCarryoverContext(userMessage, items, alternateMessage = null, llmPreDecomposeMeta = null) {
const previousAddressItem = findLastAddressAssistantItem(items);
const previousAddressDebug = previousAddressItem?.debug ?? null;
@@ -2578,9 +2650,15 @@ function resolveAddressFollowupCarryoverContext(userMessage, items, alternateMes
Boolean(followupOffer?.enabled) &&
(isImplicitAddressContinuationByLlm(userMessage, llmPreDecomposeMeta) ||
(toNonEmptyString(alternateMessage) ? isImplicitAddressContinuationByLlm(alternateMessage, llmPreDecomposeMeta) : false));
const hasPrimaryFollowupSignal = hasAddressFollowupContextSignal(userMessage);
const sourceIntentHint = toNonEmptyString(previousAddressDebug?.detected_intent);
const debtRoleSwapPrimary = sourceIntentHint ? resolveDebtRoleSwapFollowupIntent(userMessage, sourceIntentHint) : null;
const debtRoleSwapAlternate = sourceIntentHint && toNonEmptyString(alternateMessage)
? resolveDebtRoleSwapFollowupIntent(String(alternateMessage ?? ""), sourceIntentHint)
: null;
const debtRoleSwapIntent = debtRoleSwapPrimary ?? debtRoleSwapAlternate ?? null;
const hasPrimaryFollowupSignal = hasAddressFollowupContextSignal(userMessage) || Boolean(debtRoleSwapPrimary);
const hasAlternateFollowupSignal = toNonEmptyString(alternateMessage)
? hasAddressFollowupContextSignal(alternateMessage)
? hasAddressFollowupContextSignal(alternateMessage) || Boolean(debtRoleSwapAlternate)
: false;
const hasPrimaryIndexReferenceSignal = extractDisplayedEntityIndexMention(userMessage) !== null;
const hasAlternateIndexReferenceSignal = toNonEmptyString(alternateMessage)
@@ -2589,7 +2667,11 @@ function resolveAddressFollowupCarryoverContext(userMessage, items, alternateMes
const hasIndexReferenceSignal = hasPrimaryIndexReferenceSignal || hasAlternateIndexReferenceSignal;
const hasStandaloneAddressTopic = hasStandaloneAddressTopicSignal(userMessage) ||
(toNonEmptyString(alternateMessage) ? hasStandaloneAddressTopicSignal(alternateMessage) : false);
if (hasStandaloneAddressTopic && !hasImplicitContinuationSignal && !hasIndexReferenceSignal) {
if (hasStandaloneAddressTopic &&
!hasPrimaryFollowupSignal &&
!hasAlternateFollowupSignal &&
!hasImplicitContinuationSignal &&
!hasIndexReferenceSignal) {
return null;
}
if (!hasPrimaryFollowupSignal && !hasAlternateFollowupSignal && !hasImplicitContinuationSignal && !hasIndexReferenceSignal) {
@@ -2601,6 +2683,9 @@ function resolveAddressFollowupCarryoverContext(userMessage, items, alternateMes
const sourceIntent = toNonEmptyString(previousAddressDebug.detected_intent);
let previousIntent = sourceIntent;
let followupSelectionMode = "carry_previous_intent";
if (debtRoleSwapIntent) {
previousIntent = debtRoleSwapIntent;
}
if (hasImplicitContinuationSignal) {
const suggestedIntent = Array.isArray(followupOffer?.suggested_intents)
? toNonEmptyString(followupOffer.suggested_intents[0])
@@ -3106,6 +3191,13 @@ function hasSameDateAccountFollowupSignalForPredecompose(text) {
/(?:^|\s)по\s+\d{2}(?:[.,]\d{1,2})?(?=$|[\s,.;:!?])/iu.test(source) ||
/\b\d{2}(?:[.,]\d{1,2})\b/u.test(source));
}
function hasPredecomposeDiagnosticUncertaintyLead(text) {
const normalized = compactWhitespace(repairAddressMojibake(String(text ?? "")).toLowerCase());
if (!normalized) {
return false;
}
return /^(?:неясно|не\s+ясно|непонятно|не\s+понятно|unclear|not\s+clear|ambiguous|unknown)(?=$|[\s,.;:!?])/iu.test(normalized);
}
function attachAddressPredecomposeContract(meta, sourceMessage) {
const canonicalMessage = toNonEmptyString(meta?.effectiveMessage) ?? String(sourceMessage ?? "");
const predecomposeContract = (0, predecomposeContract_1.buildAddressLlmPredecomposeContractV1)({
@@ -3207,6 +3299,20 @@ async function runAddressLlmPreDecompose(normalizerService, payload, userMessage
const candidateIntentResolution = (0, addressIntentResolver_1.resolveAddressIntent)(candidate);
const sourceIntentKnown = sourceIntentResolution.intent !== "unknown";
const candidateIntentKnown = candidateIntentResolution.intent !== "unknown";
const candidateStartsWithDiagnosticUncertainty = hasPredecomposeDiagnosticUncertaintyLead(candidate);
if (candidateStartsWithDiagnosticUncertainty && sourceIntentKnown) {
return attachAddressPredecomposeContract({
...baseMeta,
attempted: true,
applied: false,
traceId: normalized?.trace_id ?? null,
llmCanonicalCandidateDetected: true,
effectiveMessage: userMessage,
reason: "normalized_fragment_rejected_diagnostic_rewrite",
fallbackRuleHit: null,
sanitizedUserMessage
}, userMessage);
}
const intentConflict = sourceIntentKnown &&
candidateIntentKnown &&
sourceIntentResolution.intent !== candidateIntentResolution.intent;
@@ -3473,6 +3579,8 @@ function resolveAddressToolGateDecision(addressInputMessage, followupContext, ll
isAddressLlmPreDecomposeCandidate(repairedInputMessage) ||
hasAccountingSignal(addressInputMessage) ||
hasAccountingSignal(repairedInputMessage) ||
hasShortDebtMirrorFollowupSignal(rawMessageForGate) ||
hasShortDebtMirrorFollowupSignal(repairedInputMessage) ||
sameDateAccountFollowupSignal;
const hasUnsupportedLowConfidencePredecomposeSignal = llmContractMode === "unsupported" &&
(llmContractModeConfidence === "low" || llmContractModeConfidence === "medium") &&
@@ -3491,6 +3599,7 @@ function resolveAddressToolGateDecision(addressInputMessage, followupContext, ll
!followupContext &&
!hasClassifierSignal &&
!hasIntentSignal &&
!hasLexicalAddressSignal &&
!strongDataSignalFromRawMessage &&
!strongDataSignalFromEffectiveMessage) {
return {
@@ -3683,7 +3792,8 @@ const ADDRESS_INTENTS_KEEP_ADDRESS_LANE = new Set([
"list_contracts_by_counterparty",
"contract_usage_overview",
"contract_usage_and_value",
"vat_payable_forecast"
"vat_payable_forecast",
"vat_payable_confirmed_as_of_date"
]);
export function resolveAssistantOrchestrationDecision(input) {
const rawUserMessage = String(input?.rawUserMessage ?? input?.userMessage ?? "");
@@ -3764,7 +3874,11 @@ export function resolveAssistantOrchestrationDecision(input) {
const explicitAddressFollowupSignal = hasAddressFollowupContextSignal(rawUserMessage) ||
hasAddressFollowupContextSignal(repairedRawUserMessage) ||
hasAddressFollowupContextSignal(effectiveAddressUserMessage) ||
hasAddressFollowupContextSignal(repairedEffectiveAddressUserMessage);
hasAddressFollowupContextSignal(repairedEffectiveAddressUserMessage) ||
hasShortDebtMirrorFollowupSignal(rawUserMessage) ||
hasShortDebtMirrorFollowupSignal(repairedRawUserMessage) ||
hasShortDebtMirrorFollowupSignal(effectiveAddressUserMessage) ||
hasShortDebtMirrorFollowupSignal(repairedEffectiveAddressUserMessage);
const effectiveAddressFollowupSignal = explicitAddressFollowupSignal && !dangerOrCoercionSignal;
const deterministicNonDomainGuard = Boolean(!dataScopeMetaQuery &&
!capabilityMetaQuery &&
@@ -3879,7 +3993,11 @@ export function resolveAssistantOrchestrationDecision(input) {
hasAddressFollowupContextSignal(rawUserMessage) ||
hasAddressFollowupContextSignal(effectiveAddressUserMessage) ||
hasAddressFollowupContextSignal(repairedRawUserMessage) ||
hasAddressFollowupContextSignal(repairedEffectiveAddressUserMessage));
hasAddressFollowupContextSignal(repairedEffectiveAddressUserMessage) ||
hasShortDebtMirrorFollowupSignal(rawUserMessage) ||
hasShortDebtMirrorFollowupSignal(effectiveAddressUserMessage) ||
hasShortDebtMirrorFollowupSignal(repairedRawUserMessage) ||
hasShortDebtMirrorFollowupSignal(repairedEffectiveAddressUserMessage));
const supportedAddressIntentDetected = !strictDeepInvestigationCueDetected &&
Boolean((intentResolution.intent && ADDRESS_INTENTS_KEEP_ADDRESS_LANE.has(intentResolution.intent)) ||
(llmContractIntent && ADDRESS_INTENTS_KEEP_ADDRESS_LANE.has(llmContractIntent)) ||
@@ -4896,14 +5014,14 @@ async function resolveAssistantDataScopeProbe() {
};
}
const catalogQueryCandidates = [
"ВЫБРАТЬ ПЕРВЫЕ 20 ПРЕДСТАВЛЕНИЕ(Организации.Ссылка) КАК Организация ИЗ Справочник.Организации КАК Организации",
"ВЫБРАТЬ ПЕРВЫЕ 20 Организации.Наименование КАК Организация ИЗ Справочник.Организации КАК Организации",
"ВЫБРАТЬ ПЕРВЫЕ 20 Организации.НаименованиеПолное КАК Организация ИЗ Справочник.Организации КАК Организации",
"ВЫБРАТЬ ПЕРВЫЕ 100 Организации.Ссылка КАК Организация, ПРЕДСТАВЛЕНИЕ(Организации.Ссылка) КАК ОрганизацияПредставление ИЗ Справочник.Организации КАК Организации"
"ВЫБРАТЬ ПЕРВЫЕ 20 ПРЕДСТАВЛЕН�?Е(Организации.Ссылка) КАК Организация �?З Справочник.Организации КАК Организации",
"ВЫБРАТЬ ПЕРВЫЕ 20 Организации.Наименование КАК Организация �?З Справочник.Организации КАК Организации",
"ВЫБРАТЬ ПЕРВЫЕ 20 Организации.НаименованиеПолное КАК Организация �?З Справочник.Организации КАК Организации",
"ВЫБРАТЬ ПЕРВЫЕ 100 Организации.Ссылка КАК Организация, ПРЕДСТАВЛЕН�?Е(Организации.Ссылка) КАК ОрганизацияПредставление �?З Справочник.Организации КАК Организации"
];
const movementProbeCandidates = [
"ВЫБРАТЬ ПЕРВЫЕ 60 Движения.Организация КАК Организация, ПРЕДСТАВЛЕНИЕ(Движения.Организация) КАК ОрганизацияПредставление ИЗ РегистрБухгалтерии.Хозрасчетный КАК Движения УПОРЯДОЧИТЬ ПО Движения.Период УБЫВ",
"ВЫБРАТЬ ПЕРВЫЕ 60 Движения.Организация КАК Организация ИЗ РегистрБухгалтерии.Хозрасчетный КАК Движения"
"ВЫБРАТЬ ПЕРВЫЕ 60 Движения.Организация КАК Организация, ПРЕДСТАВЛЕН�?Е(Движения.Организация) КАК ОрганизацияПредставление �?З РегистрБухгалтерии.Хозрасчетный КАК Движения УПОРЯДОЧ�?ТЬ ПО Движения.Период УБЫВ",
"ВЫБРАТЬ ПЕРВЫЕ 60 Движения.Организация КАК Организация �?З РегистрБухгалтерии.Хозрасчетный КАК Движения"
];
let lastError = null;
const catalogFacts = { names: [], refs: [], pairs: [] };
@@ -5034,7 +5152,7 @@ function buildAssistantOperationalBoundaryReply() {
return [
"Понимаю, что ситуация срочная.",
"Я не могу сам настраивать 1С или менять базу/конфигурацию.",
"Могу помочь безопасно: разберем симптомы и подготовим точные шаги для вашего 1С/ИТ-админа."
"Могу помочь безопасно: разберем симптомы и подготовим точные шаги для вашего 1С/�?Т-админа."
].join(" ");
}
function buildAssistantSafetyRefusalReply() {