ОРРКЕСТРАЦИЯ -Уточнить safety-policy оркестратора: останавливать loop на hard blockers и рискованных решениях, а не только по порогу 80%

This commit is contained in:
2026-04-14 08:12:12 +03:00
parent 2b48229312
commit 9048632d3e
24 changed files with 2790 additions and 36 deletions
@@ -1548,6 +1548,13 @@ function hasInventoryOnHandSignal(text: string): boolean {
if (!hasStockLexeme) {
return false;
}
if (
hasInventoryProvenanceSignalV2(text) ||
hasInventoryPurchaseDocumentsSignalV2(text) ||
hasInventorySaleTraceSignalV2(text)
) {
return false;
}
const hasGoodsLexeme =
/(?:товар(?:ы|ов|ом|а|ные)?|номенклатур|материал(?:ы|ов|а|ам)?|item(?:s)?|sku|product(?:s)?)/iu.test(text);
const hasBalanceLexeme =
@@ -1558,6 +1565,69 @@ function hasInventoryOnHandSignal(text: string): boolean {
return (hasGoodsLexeme || hasBalanceLexeme) && (hasRequestCue || hasBalanceLexeme);
}
function hasInventoryProvenanceSignal(text: string): boolean {
return /(?:поставщик|закупк|РїСЂРѕРёСЃС…РѕРРґ|откуда|РєРѕРіРґР° был куплен|активная закупк|purchase provenance|purchase date|supplier provenance|stock overlap)/iu.test(
text
);
}
function hasInventoryPurchaseDocumentsSignal(text: string): boolean {
return /(?:по каким документам|документы закупки|purchase documents|documents of purchase|through which documents|chain of documents)/iu.test(
text
);
}
function hasInventorySaleTraceSignal(text: string): boolean {
return /(?:РїСЂРѕРґР°Р|покупател|buyer|sale trace|purchase[\s-]?to[\s-]?sale|purchase -> warehouse -> sale|закупка.*РїСЂРѕРґР°Р)/iu.test(
text
);
}
function hasInventoryProvenanceSignalV2(text: string): boolean {
const hasItemCue = /(?:товар|номенклатур|sku|item|product|остат(?:ок|ки)|склад)/iu.test(text);
const hasSupplierCue = /(?:от\s+какого\s+поставщика|у\s+какого\s+поставщика|от\s+кого\s+куплен|поставщик|supplier|vendor)/iu.test(text);
const hasPurchaseCue = /(?:куплен(?:ы|а)?|закупк|происхождени|откуда|когда\s+был\s+куплен|когда\s+куплен|дата\s+закупк|purchase\s+provenance|purchase\s+date)/iu.test(text);
return hasItemCue && hasSupplierCue && hasPurchaseCue;
}
function hasInventoryPurchaseDocumentsSignalV2(text: string): boolean {
const hasItemCue = /(?:товар|номенклатур|sku|item|product)/iu.test(text);
const hasPurchaseDocCue = /(?:по\s+каким\s+документам\s+был\s+куплен|по\s+каким\s+документам\s+куплен|какими\s+документами\s+был\s+куплен|документ(?:ам|ы)\s+закупк|purchase\s+documents|documents\s+of\s+purchase|through\s+which\s+documents)/iu.test(
text
);
return hasItemCue && hasPurchaseDocCue;
}
function hasInventorySaleTraceSignalV2(text: string): boolean {
const hasItemCue = /(?:товар|номенклатур|sku|item|product)/iu.test(text);
const hasTraceCue = /(?:кому\s+был\s+продан|кто\s+купил|buyer|sale\s+trace|trace\s+of\s+sale|через\s+какие\s+документы\s+прош[её]л\s+путь\s+товара|закупк.*склад.*продаж|purchase[\s-]?to[\s-]?sale|purchase\s*->\s*warehouse\s*->\s*sale|purchase\s*->\s*stock\s*->\s*sale)/iu.test(
text
);
return hasItemCue && hasTraceCue;
}
function hasInventorySupplierStockOverlapSignal(text: string): boolean {
const hasSupplierCue = /(?:поставщик|supplier|vendor|от\s+поставщика|у\s+поставщика)/iu.test(text);
const hasStockCue = /(?:товар|номенклатур|склад|остат(?:ок|ки)|лежат|на\s+дату|по\s+состоянию\s+на\s+дату|current\s+stock|stock\s+overlap|что\s+сейчас\s+лежит)/iu.test(
text
);
return hasSupplierCue && hasStockCue;
}
function hasInventoryAgingSignal(text: string): boolean {
return /(?:стар(?:ые|ым|ых)\s+закупк|закупал(?:ись|ся)\s+очень\s+давно|очень\s+давно|давно\s+куплен|когда\s+куплен|возраст\s+остатк|aged?\s+stock|old\s+purchase|aging\s+by\s+purchase\s+date|very\s+old\s+stock)/iu.test(
text
);
}
function hasInventoryPurchaseToSaleChainSignal(text: string): boolean {
const hasSupplierCue = /(?:поставщик|supplier|vendor|от\s+кого\s+куплен)/iu.test(text);
const hasBuyerCue = /(?:покупател|buyer|customer|client|кому\s+был\s+продан)/iu.test(text);
const hasItemCue = /(?:товар|номенклатур|sku|item|product)/iu.test(text);
const hasPurchaseSaleCue = /(?:куплен(?:ы)?|закупк|позже\s+продан(?:ы)?|продан(?:ы)?|purchase|sale|цепочк[аи]\s+движен)/iu.test(text);
return (hasSupplierCue && hasBuyerCue && hasItemCue && hasPurchaseSaleCue) || /(?:purchase[\s-]?to[\s-]?sale\s+chain|закупка\s*->\s*склад\s*->\s*продажа)/iu.test(text);
}
export function resolveAddressIntent(userMessage: string): AddressIntentResolution {
const text = String(userMessage ?? "").trim().toLowerCase();
@@ -1675,6 +1745,54 @@ export function resolveAddressIntent(userMessage: string): AddressIntentResoluti
};
}
if (hasInventoryProvenanceSignalV2(text)) {
return {
intent: "inventory_purchase_provenance_for_item",
confidence: "medium",
reasons: ["inventory_provenance_signal_detected"]
};
}
if (hasInventoryPurchaseDocumentsSignalV2(text)) {
return {
intent: "inventory_purchase_documents_for_item",
confidence: "medium",
reasons: ["inventory_purchase_documents_signal_detected"]
};
}
if (hasInventoryPurchaseToSaleChainSignal(text)) {
return {
intent: "inventory_purchase_to_sale_chain",
confidence: "medium",
reasons: ["inventory_purchase_to_sale_chain_signal_detected"]
};
}
if (hasInventorySupplierStockOverlapSignal(text)) {
return {
intent: "inventory_supplier_stock_overlap_as_of_date",
confidence: "medium",
reasons: ["inventory_supplier_stock_overlap_signal_detected"]
};
}
if (hasInventoryAgingSignal(text)) {
return {
intent: "inventory_aging_by_purchase_date",
confidence: "medium",
reasons: ["inventory_aging_signal_detected"]
};
}
if (hasInventorySaleTraceSignalV2(text)) {
return {
intent: "inventory_sale_trace_for_item",
confidence: "medium",
reasons: ["inventory_sale_trace_signal_detected"]
};
}
if (hasInventoryOnHandSignal(text)) {
return {
intent: "inventory_on_hand_as_of_date",
@@ -1694,6 +1812,10 @@ export function resolveAddressIntent(userMessage: string): AddressIntentResoluti
if (
hasAny(text, OPEN_ITEMS_HINTS) &&
!hasCounterpartyDebtLongevitySignal(text) &&
!hasInventoryAgingSignal(text) &&
!hasInventoryProvenanceSignalV2(text) &&
!hasInventoryPurchaseDocumentsSignalV2(text) &&
!hasInventorySaleTraceSignalV2(text) &&
/(?:контраг|договор|контракт|counterparty|contract|покупател|клиент|заказчик|customer|client|buyer|supplier|поставщик)/iu.test(
text
)