АРЧ - Склад: сохранять полный item-anchor в selected-object sale trace и закрепить buyer follow-up регрессиями
This commit is contained in:
@@ -11,6 +11,7 @@ import * as addressQueryService_1 from "./addressQueryService";
|
||||
import * as addressQueryClassifier_1 from "./addressQueryClassifier";
|
||||
import * as addressIntentResolver_1 from "./addressIntentResolver";
|
||||
import * as addressFilterExtractor_1 from "./addressFilterExtractor";
|
||||
import * as decomposeStage_1 from "./address_runtime/decomposeStage";
|
||||
import * as predecomposeContract_1 from "./address_runtime/predecomposeContract";
|
||||
import * as openaiResponsesClient_1 from "./openaiResponsesClient";
|
||||
import * as addressMcpClient_1 from "./addressMcpClient";
|
||||
@@ -2725,8 +2726,15 @@ function hasShortInventoryObjectFollowupSignal(userMessage) {
|
||||
if (minTokens > 8) {
|
||||
return false;
|
||||
}
|
||||
const hasDirectSaleFollowupCue = (sample) => /(?:кому|каму|куда)(?:\s+\S+){0,4}\s+(?:продали|продано|продан(?:о|а|ы)?|реализовали|реализован(?:о|а|ы)?)|(?:продали|продано|реализовали|реализован(?:о|а|ы)?)(?:\s+\S+){0,4}\s+(?:кому|каму|куда)|(?:^|\s)(?:продано|продали|реализовано|реализовали)(?=$|[\s,.;:!?])/iu.test(sample);
|
||||
return samples.some((sample) => /^(?:кто|когда|документы|сумма|поставщик|покупатель)(?:\?)?$/iu.test(sample) ||
|
||||
/^(?:когда\s+(?:примерно\s+)?купили(?:\s+ее)?|каким\s+документом|покажи\s+документы|по\s+каким\s+документам|все\s+закупки|все\s+поступления|кому\s+(?:мы\s+)?продали|кто\s+купил|цепочка|путь\s+товара)(?:\?)?$/iu.test(sample));
|
||||
hasDirectSaleFollowupCue(sample) ||
|
||||
(0, decomposeStage_1.hasInventorySupplierFollowupCue)(sample) ||
|
||||
(0, decomposeStage_1.hasInventoryPurchaseDocumentsFollowupCue)(sample) ||
|
||||
(0, decomposeStage_1.hasInventoryPurchaseDateFollowupCue)(sample) ||
|
||||
(0, decomposeStage_1.hasBareInventoryPurchaseDateFollowupCue)(sample) ||
|
||||
(0, decomposeStage_1.hasInventorySaleFollowupCue)(sample) ||
|
||||
(0, decomposeStage_1.hasInventoryPurchaseToSaleChainFollowupCue)(sample));
|
||||
}
|
||||
function resolveDebtRoleSwapFollowupIntent(userMessage, previousIntent) {
|
||||
const normalized = compactWhitespace(String(userMessage ?? "").toLowerCase());
|
||||
@@ -3366,6 +3374,13 @@ function resolveRequiredAnchorTypeForIntent(intent) {
|
||||
if (intent === "list_documents_by_contract" || intent === "bank_operations_by_contract") {
|
||||
return "contract";
|
||||
}
|
||||
if (intent === "inventory_purchase_provenance_for_item" ||
|
||||
intent === "inventory_purchase_documents_for_item" ||
|
||||
intent === "inventory_sale_trace_for_item" ||
|
||||
intent === "inventory_purchase_to_sale_chain" ||
|
||||
intent === "inventory_aging_by_purchase_date") {
|
||||
return "item";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function evaluateAddressAnchorQuality(message) {
|
||||
@@ -3383,7 +3398,9 @@ function evaluateAddressAnchorQuality(message) {
|
||||
const extracted = (0, addressFilterExtractor_1.extractAddressFilters)(String(message ?? ""), intent);
|
||||
const anchorValue = anchorType === "counterparty"
|
||||
? toNonEmptyString(extracted?.extracted_filters?.counterparty)
|
||||
: toNonEmptyString(extracted?.extracted_filters?.contract);
|
||||
: anchorType === "contract"
|
||||
? toNonEmptyString(extracted?.extracted_filters?.contract)
|
||||
: toNonEmptyString(extracted?.extracted_filters?.item);
|
||||
if (!anchorValue) {
|
||||
return {
|
||||
intent,
|
||||
@@ -3394,7 +3411,9 @@ function evaluateAddressAnchorQuality(message) {
|
||||
}
|
||||
const lowQuality = anchorType === "counterparty"
|
||||
? isLowQualityPredecomposeCounterpartyAnchor(anchorValue)
|
||||
: isLowQualityPredecomposeContractAnchor(anchorValue);
|
||||
: anchorType === "contract"
|
||||
? isLowQualityPredecomposeContractAnchor(anchorValue)
|
||||
: (0, addressFilterExtractor_1.isLowQualityInventoryItemAnchorValue)(anchorValue);
|
||||
return {
|
||||
intent,
|
||||
anchorType,
|
||||
@@ -3618,6 +3637,14 @@ async function runAddressLlmPreDecompose(normalizerService, payload, userMessage
|
||||
const sourceAnchorQuality = evaluateAddressAnchorQuality(repairedSourceMessage || userMessage);
|
||||
const candidateAnchorQuality = evaluateAddressAnchorQuality(candidate);
|
||||
const sameIntentForAnchorSafety = sourceAnchorQuality.intent !== "unknown" && sourceAnchorQuality.intent === candidateAnchorQuality.intent;
|
||||
const sourceSelectedObjectItemAnchorValue = toNonEmptyString((0, addressFilterExtractor_1.extractSelectedObjectQuotedValue)(userMessage)) ??
|
||||
toNonEmptyString((0, addressFilterExtractor_1.extractSelectedObjectQuotedValue)(repairedSourceMessage || userMessage));
|
||||
const candidateSemanticItemAnchorValue = (((sameIntentForAnchorSafety &&
|
||||
sourceAnchorQuality.anchorType === "item") ||
|
||||
Boolean(sourceSelectedObjectItemAnchorValue)) &&
|
||||
candidateMeta?.semanticHints?.scope_target_kind === "item"
|
||||
? toNonEmptyString(candidateMeta.semanticHints.scope_target_text)
|
||||
: null);
|
||||
const counterpartyAnchorSubstitutedByCandidate = sameIntentForAnchorSafety &&
|
||||
sourceAnchorQuality.anchorType === "counterparty" &&
|
||||
sourceAnchorQuality.quality >= 2 &&
|
||||
@@ -3642,6 +3669,25 @@ async function runAddressLlmPreDecompose(normalizerService, payload, userMessage
|
||||
semanticHints: candidateMeta?.semanticHints ?? null
|
||||
}, userMessage);
|
||||
}
|
||||
const itemSemanticAnchorDegradedByCandidate = (sameIntentForAnchorSafety ||
|
||||
Boolean(sourceSelectedObjectItemAnchorValue)) &&
|
||||
Boolean(sourceSelectedObjectItemAnchorValue ?? sourceAnchorQuality.anchorValue) &&
|
||||
Boolean(candidateSemanticItemAnchorValue) &&
|
||||
(0, addressFilterExtractor_1.isInventoryItemAnchorDegradation)(sourceSelectedObjectItemAnchorValue ?? sourceAnchorQuality.anchorValue ?? "", candidateSemanticItemAnchorValue ?? "");
|
||||
if (itemSemanticAnchorDegradedByCandidate) {
|
||||
return attachAddressPredecomposeContract({
|
||||
...baseMeta,
|
||||
attempted: true,
|
||||
applied: false,
|
||||
traceId: normalized?.trace_id ?? null,
|
||||
llmCanonicalCandidateDetected: true,
|
||||
effectiveMessage: userMessage,
|
||||
reason: "normalized_fragment_rejected_anchor_degradation",
|
||||
fallbackRuleHit: null,
|
||||
sanitizedUserMessage,
|
||||
semanticHints: candidateMeta?.semanticHints ?? null
|
||||
}, userMessage);
|
||||
}
|
||||
const anchorDegradedByCandidate = sameIntentForAnchorSafety &&
|
||||
sourceAnchorQuality.anchorType &&
|
||||
sourceAnchorQuality.quality >= 2 &&
|
||||
|
||||
Reference in New Issue
Block a user