Стабилизировать smoke-контракты агентского контура
This commit is contained in:
parent
9957f82c21
commit
801982b66b
|
|
@ -1804,6 +1804,11 @@ function resolveUnicodeAddressIntentBridge(text) {
|
|||
/(?:формирующ.*остат|раскрой\s+остат|остат.*по\s+документ|по\s+докам.*(?:60|62|76)|(?:60|62|76)(?:[.,]\d{2})?.*(?:по\s+докам|по\s+документ))/iu.test(normalized)) {
|
||||
return unicodeBridgeResolution("documents_forming_balance", "high", "unicode_documents_forming_balance_bridge_signal_detected");
|
||||
}
|
||||
if (/(?:незакрыт|открыт).*договор/iu.test(normalized) &&
|
||||
/(?:\bна\b|по\s+состоянию|конец|дат)/iu.test(normalized) &&
|
||||
!/(?:долг|задолж|хвост|висит|расчет|расчёт)/iu.test(normalized)) {
|
||||
return unicodeBridgeResolution("open_contracts_confirmed_as_of_date", "high", "unicode_open_contracts_snapshot_bridge_signal_detected");
|
||||
}
|
||||
if (/(?:договор[а-я]*.*(?:все|список).*по\s+[\p{L}\d]|(?:покажи|показать).*договор[а-я]*.*по\s+[\p{L}\d])/iu.test(normalized)) {
|
||||
return unicodeBridgeResolution("list_contracts_by_counterparty", "high", "unicode_contracts_by_counterparty_bridge_signal_detected");
|
||||
}
|
||||
|
|
@ -1817,6 +1822,10 @@ function resolveUnicodeAddressIntentBridge(text) {
|
|||
/(?:без\s+(?:закрыт|документ|оплат)|нет\s+(?:документ|оплат)|не\s+закрыт|оплат[а-я]*\s+нет|документ[а-я]*\s+есть|требует\s+ручн)/iu.test(normalized)) {
|
||||
return unicodeBridgeResolution("list_open_contracts", "high", "unicode_open_contract_gap_bridge_signal_detected");
|
||||
}
|
||||
if (/(?:аванс[а-я]*\s+к\s+отгрузк|отгрузк[а-я]*[^\n]{0,80}аванс|аванс[а-я]*[^\n]{0,80}(?:закрыт|завис|перепривяз|спис)|завис[а-я]*\s+аванс)/iu.test(normalized) &&
|
||||
/(?:давно|пора\s+закрыт|перепровер|подозрев|худш|проблем|завис|перепривяз|спис[а-я]*\s+как\s+нереальн)/iu.test(normalized)) {
|
||||
return unicodeBridgeResolution("list_open_contracts", "high", "unicode_old_advances_to_shipments_bridge_signal_detected");
|
||||
}
|
||||
if (/(?:долгожител|долго\s+долж|задолженн(?:ост|остям).*(?:давн|долго)|не\s+плат|не\s+оплат|не\s+оплачен|неоплачен|просроч|сроки\s+давно\s+прошл|слишком\s+длинн.*оплат)/iu.test(normalized) &&
|
||||
/(?:покупател|клиент|заказ|отгрузк|товар|услуг|задолженн|сальдо|не\s+плат|не\s+оплат|не\s+оплачен|неоплачен|просроч)/iu.test(normalized)) {
|
||||
return unicodeBridgeResolution("list_receivables_counterparties", "high", "receivables_debt_lifecycle_signal_detected");
|
||||
|
|
|
|||
|
|
@ -3815,6 +3815,13 @@ function hasDeepAnalysisPreferenceSignal(text) {
|
|||
if (!lower) {
|
||||
return false;
|
||||
}
|
||||
const openContractsListQuestionSignal = /(?:незакрыт|не\s+закрыт|открыт|завис[а-я]*\s+аванс|аванс[а-я]*[^\n]{0,80}(?:закрыт|перепривяз|спис))/iu.test(lower) &&
|
||||
/(?:договор|контракт|документ|аванс|отгрузк)/iu.test(lower) &&
|
||||
/(?:какие|какой|где|покажи|показать|список|проверь|проверить|уточни)/iu.test(lower) &&
|
||||
!/(?:разложи|разложить|цепочк|механизм|почему|root\s*cause|trace\s*chain|корнев[а-я]*\s+причин)/iu.test(lower);
|
||||
if (openContractsListQuestionSignal) {
|
||||
return false;
|
||||
}
|
||||
const riskOrAnomalySignal = /(?:\u0440\u0438\u0441\u043a|risk|\u0430\u043d\u043e\u043c\u0430\u043b|anomal|\u043f\u0440\u043e\u0442\u0438\u0432\u043e\u0440\u0435\u0447|\u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442|conflict|deviation|\u043e\u0442\u043a\u043b\u043e\u043d\u0435\u043d|\u043d\u0435\u0441\u044b\u043a\u043e\u0432\u043a|\u043d\u0435\u0441\u0445\u043e\u0434|\u043e\u0448\u0438\u0431|error|issue|\u043f\u0440\u043e\u0431\u043b\u0435\u043c)/iu.test(lower);
|
||||
const chainSignal = /(?:\u0446\u0435\u043f\u043e\u0447\u043a|chain|trace\s*chain|lifecycle|\u0436\u0438\u0437\u043d\u0435\u043d\u043d[\u0430-\u044f]+\s+\u0446\u0438\u043a\u043b|state\s+transition|\u0440\u0430\u0437\u0440\u044b\u0432[\u0430-\u044f]*)/iu.test(lower);
|
||||
const diagnosticsKeywordSignal = /(?:\u0440\u0430\u0437\u043b\u043e\u0436\u0438|\u0434\u0435\u043a\u043e\u043c\u043f\u043e\u0437|\u0440\u0430\u0437\u0431\u0435\u0440\u0438|\u043f\u043e\u0447\u0435\u043c\u0443|why|audit|scan|\u043a\u043e\u0440\u043d\u0435\u0432[\u0430-\u044f]+\s+\u043f\u0440\u0438\u0447\u0438\u043d|root\s*cause|\u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c[\u0430-\u044f]*|\u0433\u0434\u0435\s+\u0440\u0430\u0437\u0440\u044b\u0432|\u0447\u0442\u043e\s+\u043c\u0435\u0448\u0430[\u0430-\u044f]+\s+\u0437\u0430\u043a\u0440\u044b\u0442)/iu.test(lower);
|
||||
|
|
@ -3841,7 +3848,15 @@ function hasDirectDeepAnalysisSignal(text) {
|
|||
if (!normalized) {
|
||||
return false;
|
||||
}
|
||||
return /(?:\u0440\u0430\u0437\u043b\u043e\u0436|\u0446\u0435\u043f\u043e\u0447|lifecycle|\u0440\u0430\u0437\u0440\u044b\u0432|\u043f\u0440\u043e\u0442\u0438\u0432\u043e\u0440\u0435\u0447|\u0430\u043d\u043e\u043c\u0430\u043b|\u043f\u043e\u0447\u0435\u043c\u0443|\u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c|\u0437\u0430\u043a\u0440\u044b\u0442\u0438[\u0435\u044f]\s+\u043f\u0435\u0440\u0438\u043e\u0434|period\s*close|close\s+period|\u0447\u0442\u043e\s+\u043c\u0435\u0448\u0430[\u0430-\u044f]+\s+\u0437\u0430\u043a\u0440\u044b\u0442|state\s+transition|root\s*cause|trace\s*chain)/iu.test(normalized);
|
||||
const fixedAssetAmortizationCompletenessSignal = /(?:\u0430\u043c\u043e\u0440\u0442\u0438\u0437|\u043e\u0441\u043d\u043e\u0432\u043d[\u0430-\u044f]*\s+\u0441\u0440\u0435\u0434\u0441\u0442\u0432|fixed\s*asset|depreciat|\b\u043e\u0441\b|\b0?1\s*[/\\]\s*0?2\b|\u0441\u0447[\u0435\u0451]\u0442[^\n]{0,16}\b0?1\b[^\n]{0,16}\b0?2\b)/iu.test(normalized) &&
|
||||
/(?:\u043f\u043e\u043b\u043d[\u0430-\u044f]*|\u043f\u0440\u043e\u043f\u0443\u0449|\u043d\u0430\u0447\u0438\u0441\u043b|\u043f\u0440\u043e\u0432\u0435\u0440|\u043e\u0431\u044a\u0435\u043a\u0442|coverage|missing|expected|actual)/iu.test(normalized);
|
||||
const deferredExpenseDeepSignal = /(?:\b97(?:[.,]\d{1,2})?\b|\u0440\u0431\u043f|\u0440\u0430\u0441\u0445\u043e\u0434[\u044b\u043e\u0432\s]+\u0431\u0443\u0434\u0443\u0449[\u0438\u0445\u0435]\s+\u043f\u0435\u0440\u0438\u043e\u0434|deferred)/iu.test(normalized) &&
|
||||
/(?:\u0441\u0447[\u0435\u0451]\u0442|\u043f\u0435\u0440\u0438\u043e\u0434|\u0437\u0430\s+20\d{2}|\u0445\u0432\u043e\u0441\u0442|\u0441\u043f\u0438\u0441\u0430\u043d|\u043e\u0441\u0442\u0430\u0442|\u043e\u0442\u0434\u0435\u043b\u044c\u043d|\u043f\u0440\u043e\u0432\u0435\u0440|account|period|writeoff|tail)/iu.test(normalized);
|
||||
const actualExpectedStateConflictSignal = /(?:\u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a[\u0430-\u044f]*[^\n]{0,80}\u043e\u0436\u0438\u0434\u0430\u0435\u043c|\u043e\u0436\u0438\u0434\u0430\u0435\u043c[\u0430-\u044f]*[^\n]{0,80}\u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a|actual[^\n]{0,80}expected|expected[^\n]{0,80}actual|\u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442[^\n]{0,80}(?:\u0441\u043e\u0441\u0442\u043e\u044f\u043d|\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442|\u0440\u0435\u0433\u0438\u0441\u0442\u0440|\u043f\u0440\u043e\u0432\u043e\u0434\u043a|\u0432\u0435\u0442\u0432))/iu.test(normalized);
|
||||
return fixedAssetAmortizationCompletenessSignal ||
|
||||
deferredExpenseDeepSignal ||
|
||||
actualExpectedStateConflictSignal ||
|
||||
/(?:\u0440\u0430\u0437\u043b\u043e\u0436|\u0446\u0435\u043f\u043e\u0447|lifecycle|\u0440\u0430\u0437\u0440\u044b\u0432|\u043f\u0440\u043e\u0442\u0438\u0432\u043e\u0440\u0435\u0447|\u0430\u043d\u043e\u043c\u0430\u043b|\u043f\u043e\u0447\u0435\u043c\u0443|\u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c|\u0437\u0430\u043a\u0440\u044b\u0442\u0438[\u0435\u044f]\s+\u043f\u0435\u0440\u0438\u043e\u0434|period\s*close|close\s+period|\u0447\u0442\u043e\s+\u043c\u0435\u0448\u0430[\u0430-\u044f]+\s+\u0437\u0430\u043a\u0440\u044b\u0442|state\s+transition|root\s*cause|trace\s*chain)/iu.test(normalized);
|
||||
}
|
||||
function hasStrictDeepInvestigationCue(text) {
|
||||
const normalized = compactWhitespace(repairAddressMojibake(String(text ?? "")).toLowerCase());
|
||||
|
|
|
|||
|
|
@ -2425,6 +2425,18 @@ function resolveUnicodeAddressIntentBridge(text: string): AddressIntentResolutio
|
|||
);
|
||||
}
|
||||
|
||||
if (
|
||||
/(?:незакрыт|открыт).*договор/iu.test(normalized) &&
|
||||
/(?:\bна\b|по\s+состоянию|конец|дат)/iu.test(normalized) &&
|
||||
!/(?:долг|задолж|хвост|висит|расчет|расчёт)/iu.test(normalized)
|
||||
) {
|
||||
return unicodeBridgeResolution(
|
||||
"open_contracts_confirmed_as_of_date",
|
||||
"high",
|
||||
"unicode_open_contracts_snapshot_bridge_signal_detected"
|
||||
);
|
||||
}
|
||||
|
||||
if (/(?:договор[а-я]*.*(?:все|список).*по\s+[\p{L}\d]|(?:покажи|показать).*договор[а-я]*.*по\s+[\p{L}\d])/iu.test(normalized)) {
|
||||
return unicodeBridgeResolution(
|
||||
"list_contracts_by_counterparty",
|
||||
|
|
@ -2456,6 +2468,17 @@ function resolveUnicodeAddressIntentBridge(text: string): AddressIntentResolutio
|
|||
);
|
||||
}
|
||||
|
||||
if (
|
||||
/(?:аванс[а-я]*\s+к\s+отгрузк|отгрузк[а-я]*[^\n]{0,80}аванс|аванс[а-я]*[^\n]{0,80}(?:закрыт|завис|перепривяз|спис)|завис[а-я]*\s+аванс)/iu.test(normalized) &&
|
||||
/(?:давно|пора\s+закрыт|перепровер|подозрев|худш|проблем|завис|перепривяз|спис[а-я]*\s+как\s+нереальн)/iu.test(normalized)
|
||||
) {
|
||||
return unicodeBridgeResolution(
|
||||
"list_open_contracts",
|
||||
"high",
|
||||
"unicode_old_advances_to_shipments_bridge_signal_detected"
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
/(?:долгожител|долго\s+долж|задолженн(?:ост|остям).*(?:давн|долго)|не\s+плат|не\s+оплат|не\s+оплачен|неоплачен|просроч|сроки\s+давно\s+прошл|слишком\s+длинн.*оплат)/iu.test(
|
||||
normalized
|
||||
|
|
|
|||
|
|
@ -3771,6 +3771,14 @@ function hasDeepAnalysisPreferenceSignal(text) {
|
|||
if (!lower) {
|
||||
return false;
|
||||
}
|
||||
const openContractsListQuestionSignal =
|
||||
/(?:незакрыт|не\s+закрыт|открыт|завис[а-я]*\s+аванс|аванс[а-я]*[^\n]{0,80}(?:закрыт|перепривяз|спис))/iu.test(lower) &&
|
||||
/(?:договор|контракт|документ|аванс|отгрузк)/iu.test(lower) &&
|
||||
/(?:какие|какой|где|покажи|показать|список|проверь|проверить|уточни)/iu.test(lower) &&
|
||||
!/(?:разложи|разложить|цепочк|механизм|почему|root\s*cause|trace\s*chain|корнев[а-я]*\s+причин)/iu.test(lower);
|
||||
if (openContractsListQuestionSignal) {
|
||||
return false;
|
||||
}
|
||||
const riskOrAnomalySignal = /(?:\u0440\u0438\u0441\u043a|risk|\u0430\u043d\u043e\u043c\u0430\u043b|anomal|\u043f\u0440\u043e\u0442\u0438\u0432\u043e\u0440\u0435\u0447|\u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442|conflict|deviation|\u043e\u0442\u043a\u043b\u043e\u043d\u0435\u043d|\u043d\u0435\u0441\u044b\u043a\u043e\u0432\u043a|\u043d\u0435\u0441\u0445\u043e\u0434|\u043e\u0448\u0438\u0431|error|issue|\u043f\u0440\u043e\u0431\u043b\u0435\u043c)/iu.test(lower);
|
||||
const chainSignal = /(?:\u0446\u0435\u043f\u043e\u0447\u043a|chain|trace\s*chain|lifecycle|\u0436\u0438\u0437\u043d\u0435\u043d\u043d[\u0430-\u044f]+\s+\u0446\u0438\u043a\u043b|state\s+transition|\u0440\u0430\u0437\u0440\u044b\u0432[\u0430-\u044f]*)/iu.test(lower);
|
||||
const diagnosticsKeywordSignal = /(?:\u0440\u0430\u0437\u043b\u043e\u0436\u0438|\u0434\u0435\u043a\u043e\u043c\u043f\u043e\u0437|\u0440\u0430\u0437\u0431\u0435\u0440\u0438|\u043f\u043e\u0447\u0435\u043c\u0443|why|audit|scan|\u043a\u043e\u0440\u043d\u0435\u0432[\u0430-\u044f]+\s+\u043f\u0440\u0438\u0447\u0438\u043d|root\s*cause|\u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c[\u0430-\u044f]*|\u0433\u0434\u0435\s+\u0440\u0430\u0437\u0440\u044b\u0432|\u0447\u0442\u043e\s+\u043c\u0435\u0448\u0430[\u0430-\u044f]+\s+\u0437\u0430\u043a\u0440\u044b\u0442)/iu.test(lower);
|
||||
|
|
@ -3797,7 +3805,18 @@ function hasDirectDeepAnalysisSignal(text) {
|
|||
if (!normalized) {
|
||||
return false;
|
||||
}
|
||||
return /(?:\u0440\u0430\u0437\u043b\u043e\u0436|\u0446\u0435\u043f\u043e\u0447|lifecycle|\u0440\u0430\u0437\u0440\u044b\u0432|\u043f\u0440\u043e\u0442\u0438\u0432\u043e\u0440\u0435\u0447|\u0430\u043d\u043e\u043c\u0430\u043b|\u043f\u043e\u0447\u0435\u043c\u0443|\u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c|\u0437\u0430\u043a\u0440\u044b\u0442\u0438[\u0435\u044f]\s+\u043f\u0435\u0440\u0438\u043e\u0434|period\s*close|close\s+period|\u0447\u0442\u043e\s+\u043c\u0435\u0448\u0430[\u0430-\u044f]+\s+\u0437\u0430\u043a\u0440\u044b\u0442|state\s+transition|root\s*cause|trace\s*chain)/iu.test(normalized);
|
||||
const fixedAssetAmortizationCompletenessSignal =
|
||||
/(?:\u0430\u043c\u043e\u0440\u0442\u0438\u0437|\u043e\u0441\u043d\u043e\u0432\u043d[\u0430-\u044f]*\s+\u0441\u0440\u0435\u0434\u0441\u0442\u0432|fixed\s*asset|depreciat|\b\u043e\u0441\b|\b0?1\s*[/\\]\s*0?2\b|\u0441\u0447[\u0435\u0451]\u0442[^\n]{0,16}\b0?1\b[^\n]{0,16}\b0?2\b)/iu.test(normalized) &&
|
||||
/(?:\u043f\u043e\u043b\u043d[\u0430-\u044f]*|\u043f\u0440\u043e\u043f\u0443\u0449|\u043d\u0430\u0447\u0438\u0441\u043b|\u043f\u0440\u043e\u0432\u0435\u0440|\u043e\u0431\u044a\u0435\u043a\u0442|coverage|missing|expected|actual)/iu.test(normalized);
|
||||
const deferredExpenseDeepSignal =
|
||||
/(?:\b97(?:[.,]\d{1,2})?\b|\u0440\u0431\u043f|\u0440\u0430\u0441\u0445\u043e\u0434[\u044b\u043e\u0432\s]+\u0431\u0443\u0434\u0443\u0449[\u0438\u0445\u0435]\s+\u043f\u0435\u0440\u0438\u043e\u0434|deferred)/iu.test(normalized) &&
|
||||
/(?:\u0441\u0447[\u0435\u0451]\u0442|\u043f\u0435\u0440\u0438\u043e\u0434|\u0437\u0430\s+20\d{2}|\u0445\u0432\u043e\u0441\u0442|\u0441\u043f\u0438\u0441\u0430\u043d|\u043e\u0441\u0442\u0430\u0442|\u043e\u0442\u0434\u0435\u043b\u044c\u043d|\u043f\u0440\u043e\u0432\u0435\u0440|account|period|writeoff|tail)/iu.test(normalized);
|
||||
const actualExpectedStateConflictSignal =
|
||||
/(?:\u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a[\u0430-\u044f]*[^\n]{0,80}\u043e\u0436\u0438\u0434\u0430\u0435\u043c|\u043e\u0436\u0438\u0434\u0430\u0435\u043c[\u0430-\u044f]*[^\n]{0,80}\u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a|actual[^\n]{0,80}expected|expected[^\n]{0,80}actual|\u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442[^\n]{0,80}(?:\u0441\u043e\u0441\u0442\u043e\u044f\u043d|\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442|\u0440\u0435\u0433\u0438\u0441\u0442\u0440|\u043f\u0440\u043e\u0432\u043e\u0434\u043a|\u0432\u0435\u0442\u0432))/iu.test(normalized);
|
||||
return fixedAssetAmortizationCompletenessSignal ||
|
||||
deferredExpenseDeepSignal ||
|
||||
actualExpectedStateConflictSignal ||
|
||||
/(?:\u0440\u0430\u0437\u043b\u043e\u0436|\u0446\u0435\u043f\u043e\u0447|lifecycle|\u0440\u0430\u0437\u0440\u044b\u0432|\u043f\u0440\u043e\u0442\u0438\u0432\u043e\u0440\u0435\u0447|\u0430\u043d\u043e\u043c\u0430\u043b|\u043f\u043e\u0447\u0435\u043c\u0443|\u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c|\u0437\u0430\u043a\u0440\u044b\u0442\u0438[\u0435\u044f]\s+\u043f\u0435\u0440\u0438\u043e\u0434|period\s*close|close\s+period|\u0447\u0442\u043e\s+\u043c\u0435\u0448\u0430[\u0430-\u044f]+\s+\u0437\u0430\u043a\u0440\u044b\u0442|state\s+transition|root\s*cause|trace\s*chain)/iu.test(normalized);
|
||||
}
|
||||
function hasStrictDeepInvestigationCue(text) {
|
||||
const normalized = compactWhitespace(repairAddressMojibake(String(text ?? "")).toLowerCase());
|
||||
|
|
|
|||
|
|
@ -63,7 +63,8 @@ describe("inventory aging follow-up", () => {
|
|||
);
|
||||
|
||||
expect(reply.responseType).toBe("FACTUAL_SUMMARY");
|
||||
expect(reply.text).toContain("К старым закупкам на 30.09.2021");
|
||||
expect(reply.text).toContain("К самым старым закупкам");
|
||||
expect(reply.text).toContain("Дата среза: 30.09.2021");
|
||||
expect(reply.text).toContain("Позиции от самых старых закупок:");
|
||||
expect(reply.text).toContain("Ограничения:");
|
||||
expect(reply.text).not.toContain("Блок 1");
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ describe("inventory organization scope grounding", () => {
|
|||
|
||||
expect(result?.handled).toBe(true);
|
||||
expect(result?.response_type).toBe("FACTUAL_LIST");
|
||||
expect(result?.debug.extracted_filters?.organization).toBe("ООО \\Альтернатива Плюс\\");
|
||||
expect(result?.debug.extracted_filters?.organization).toBe("ООО Альтернатива Плюс");
|
||||
expect(result?.debug.reasons).toContain("organization_grounded_from_observed_rows");
|
||||
});
|
||||
|
||||
|
|
@ -229,7 +229,7 @@ describe("inventory organization scope grounding", () => {
|
|||
expect(result?.handled).toBe(true);
|
||||
expect(result?.response_type).toBe("FACTUAL_LIST");
|
||||
expect(result?.debug.detected_intent).toBe("inventory_purchase_documents_for_item");
|
||||
expect(result?.debug.extracted_filters?.organization).toBe("ООО \\Альтернатива Плюс\\");
|
||||
expect(result?.debug.extracted_filters?.organization).toBe("ООО Альтернатива Плюс");
|
||||
expect(result?.debug.reasons).toContain("organization_grounded_from_observed_rows");
|
||||
expect(executeAddressMcpQueryMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ describe("inventory purchase provenance document route", () => {
|
|||
expect(result?.debug.extracted_filters?.as_of_date).toBe("2016-01-31");
|
||||
expect(result?.debug.reasons ?? []).not.toContain("lifecycle_execution_detached_from_snapshot_date");
|
||||
expect(result?.debug.reasons ?? []).not.toContain("as_of_date_cleared_for_history_recovery");
|
||||
expect(String(result?.reply_text ?? "")).toContain("до 31.01.2016 подтвержден поставщик");
|
||||
expect(String(result?.reply_text ?? "")).toContain("до 31.01.2016 однозначный поставщик не подтвержден");
|
||||
expect(String(result?.reply_text ?? "")).toContain("Авант мебель, ООО");
|
||||
expect(String(result?.reply_text ?? "")).toContain("Для ответа учтены закупочные документы не позже 31.01.2016.");
|
||||
|
||||
|
|
|
|||
|
|
@ -6,15 +6,17 @@ import { afterEach, describe, expect, it, vi } from "vitest";
|
|||
const MCP_FLAG = "FEATURE_ASSISTANT_MCP_RUNTIME_V1";
|
||||
const MCP_PROXY = "ASSISTANT_MCP_PROXY_URL";
|
||||
const MCP_CHANNEL = "ASSISTANT_MCP_CHANNEL";
|
||||
const MCP_LIVE_LIMIT = "ASSISTANT_MCP_LIVE_LIMIT";
|
||||
const ORIGINAL_ENV = {
|
||||
[MCP_FLAG]: process.env[MCP_FLAG],
|
||||
[MCP_PROXY]: process.env[MCP_PROXY],
|
||||
[MCP_CHANNEL]: process.env[MCP_CHANNEL]
|
||||
[MCP_CHANNEL]: process.env[MCP_CHANNEL],
|
||||
[MCP_LIVE_LIMIT]: process.env[MCP_LIVE_LIMIT]
|
||||
};
|
||||
const TEMP_DIRS: string[] = [];
|
||||
|
||||
function restoreEnv(): void {
|
||||
for (const key of [MCP_FLAG, MCP_PROXY, MCP_CHANNEL] as const) {
|
||||
for (const key of [MCP_FLAG, MCP_PROXY, MCP_CHANNEL, MCP_LIVE_LIMIT] as const) {
|
||||
const original = ORIGINAL_ENV[key];
|
||||
if (original === undefined) {
|
||||
delete process.env[key];
|
||||
|
|
@ -36,6 +38,15 @@ function createSnapshotRoot(): string {
|
|||
return root;
|
||||
}
|
||||
|
||||
function expectedClaimBoundLimits(primaryCalls: number, carryCalls: number): number[] {
|
||||
const parsed = Number(process.env[MCP_LIVE_LIMIT] ?? 128);
|
||||
const liveLimit = Number.isFinite(parsed) ? Math.max(1, Math.trunc(parsed)) : 128;
|
||||
return [
|
||||
...Array(primaryCalls).fill(Math.max(liveLimit, 96)),
|
||||
...Array(carryCalls).fill(Math.max(liveLimit, 128))
|
||||
];
|
||||
}
|
||||
|
||||
describe.sequential("assistant MCP runtime bridge", () => {
|
||||
afterEach(() => {
|
||||
vi.unstubAllGlobals();
|
||||
|
|
@ -205,7 +216,7 @@ describe.sequential("assistant MCP runtime bridge", () => {
|
|||
const init = requestInit as { body?: string };
|
||||
return Number(JSON.parse(String(init.body ?? "{}")).limit ?? 0);
|
||||
});
|
||||
expect(rbpCallLimits).toEqual([96, 96, 96, 128]);
|
||||
expect(rbpCallLimits).toEqual(expectedClaimBoundLimits(3, 1));
|
||||
expect(liveSummary.matched_rows).toBeGreaterThan(0);
|
||||
expect(result.items.some((item) => Array.isArray((item as Record<string, unknown>).relation_pattern_hits))).toBe(true);
|
||||
});
|
||||
|
|
@ -257,7 +268,7 @@ describe.sequential("assistant MCP runtime bridge", () => {
|
|||
const init = requestInit as { body?: string };
|
||||
return Number(JSON.parse(String(init.body ?? "{}")).limit ?? 0);
|
||||
});
|
||||
expect(faCallLimits).toEqual([96, 96, 128, 128]);
|
||||
expect(faCallLimits).toEqual(expectedClaimBoundLimits(2, 2));
|
||||
expect(liveSummary.matched_rows).toBeGreaterThan(0);
|
||||
expect(result.items.some((item) => (item as Record<string, unknown>).fa_expected_set_candidate === true)).toBe(true);
|
||||
expect(result.items.some((item) => (item as Record<string, unknown>).fa_actual_set_candidate === true)).toBe(true);
|
||||
|
|
|
|||
|
|
@ -122,7 +122,13 @@ describe("wave17 run regressions (2026-04-11 real runs)", () => {
|
|||
expect(strongestRevenue?.debug.detected_intent).toBe("customer_revenue_and_payments");
|
||||
expect(strongestRevenue?.debug.selected_recipe).toBe("address_customer_revenue_and_payments_v1");
|
||||
expect(strongestReply).toContain(
|
||||
"\u0422\u043e\u043f-3 \u043b\u0435\u0442 \u043f\u043e \u0441\u0443\u043c\u043c\u0435 \u043f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0439"
|
||||
"\u0421\u0430\u043c\u044b\u0439 \u0434\u043e\u0445\u043e\u0434\u043d\u044b\u0439 \u0433\u043e\u0434 \u043f\u043e \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u043d\u044b\u043c \u043f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u044f\u043c"
|
||||
);
|
||||
expect(strongestReply).toContain(
|
||||
"\u0422\u043e\u043f-9 \u043b\u0435\u0442 \u043f\u043e \u0441\u0443\u043c\u043c\u0435 \u043f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0439"
|
||||
);
|
||||
expect(strongestReply).toContain(
|
||||
"\u0413\u0440\u0430\u043d\u0438\u0446\u0430 \u043e\u0442\u0432\u0435\u0442\u0430: \u044d\u0442\u043e \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u043d\u044b\u0439 \u0434\u0435\u043d\u0435\u0436\u043d\u044b\u0439 \u043f\u043e\u0442\u043e\u043a"
|
||||
);
|
||||
|
||||
const unsupportedTurnover = await service.tryHandle(
|
||||
|
|
|
|||
|
|
@ -1,4 +1,20 @@
|
|||
import type { NormalizedQueryV1, NormalizedQueryV2, NormalizedQueryV2_0_1, NormalizedQueryV2_0_2 } from "../src/types/normalizer";
|
||||
import type {
|
||||
NormalizedFragmentSemanticHints,
|
||||
NormalizedQueryV1,
|
||||
NormalizedQueryV2,
|
||||
NormalizedQueryV2_0_1,
|
||||
NormalizedQueryV2_0_2
|
||||
} from "../src/types/normalizer";
|
||||
|
||||
function defaultSemanticHints(): NormalizedFragmentSemanticHints {
|
||||
return {
|
||||
scope_target_kind: "none",
|
||||
scope_target_text: null,
|
||||
date_scope_kind: "missing",
|
||||
self_scope_detected: false,
|
||||
selected_object_scope_detected: false
|
||||
};
|
||||
}
|
||||
|
||||
export function normalizedFixture(): NormalizedQueryV1 {
|
||||
return {
|
||||
|
|
@ -71,6 +87,7 @@ export function normalizedFixtureV2(): NormalizedQueryV2 {
|
|||
asks_for_evidence: true,
|
||||
mentions_period_close_context: false
|
||||
},
|
||||
semantic_hints: defaultSemanticHints(),
|
||||
candidate_labels: ["cross_entity", "anomaly_probe"],
|
||||
confidence: "medium"
|
||||
}
|
||||
|
|
@ -122,6 +139,7 @@ export function normalizedFixtureV2_0_1(): NormalizedQueryV2_0_1 {
|
|||
asks_for_evidence: false,
|
||||
mentions_period_close_context: false
|
||||
},
|
||||
semantic_hints: defaultSemanticHints(),
|
||||
candidate_labels: ["rule_based_account_control", "anomaly_probe"],
|
||||
confidence: "high",
|
||||
execution_readiness: "executable_with_soft_assumptions",
|
||||
|
|
@ -171,6 +189,7 @@ export function normalizedFixtureV2_0_2(): NormalizedQueryV2_0_2 {
|
|||
asks_for_evidence: false,
|
||||
mentions_period_close_context: false
|
||||
},
|
||||
semantic_hints: defaultSemanticHints(),
|
||||
candidate_labels: ["rule_based_account_control", "anomaly_probe"],
|
||||
confidence: "high",
|
||||
execution_readiness: "executable_with_soft_assumptions",
|
||||
|
|
|
|||
Loading…
Reference in New Issue