ARCH: защитить document→payments pivot от discovery override
This commit is contained in:
@@ -391,6 +391,34 @@ function hasMatchedFactualAddressContinuationTarget(
|
||||
return Boolean(detectedIntent && targetIntent && detectedIntent === targetIntent);
|
||||
}
|
||||
|
||||
function hasMatchedFactualSuggestedIntentPivotTarget(
|
||||
input: ApplyAssistantMcpDiscoveryResponsePolicyInput,
|
||||
entryPoint: AssistantMcpDiscoveryRuntimeEntryPointContract | null
|
||||
): boolean {
|
||||
if (!isDiscoveryReadyAddressCandidate(input, entryPoint)) {
|
||||
return false;
|
||||
}
|
||||
if (!hasEffectivelyFactualAddressReply(input)) {
|
||||
return false;
|
||||
}
|
||||
const detectedIntent = toNonEmptyString(input.addressRuntimeMeta?.detected_intent);
|
||||
const dialogContinuationContract =
|
||||
toRecordObject(input.addressRuntimeMeta?.dialogContinuationContract) ??
|
||||
toRecordObject(input.addressRuntimeMeta?.dialog_continuation_contract_v2);
|
||||
const targetIntent = toNonEmptyString(dialogContinuationContract?.target_intent);
|
||||
const decision = toNonEmptyString(dialogContinuationContract?.decision);
|
||||
const selectionMode = toNonEmptyString(dialogContinuationContract?.intent_selection_mode);
|
||||
const suggestedPivotSignal = dialogContinuationContract?.suggested_intent_pivot_signal === true;
|
||||
return Boolean(
|
||||
detectedIntent &&
|
||||
targetIntent &&
|
||||
detectedIntent === targetIntent &&
|
||||
(decision === "switch_to_suggested" ||
|
||||
selectionMode === "switch_to_suggested_intent" ||
|
||||
suggestedPivotSignal)
|
||||
);
|
||||
}
|
||||
|
||||
function hasFullConfirmedFactualAddressReply(
|
||||
input: ApplyAssistantMcpDiscoveryResponsePolicyInput,
|
||||
entryPoint: AssistantMcpDiscoveryRuntimeEntryPointContract | null
|
||||
@@ -433,6 +461,7 @@ export function applyAssistantMcpDiscoveryResponsePolicy(
|
||||
const alignedFactualAddressReply = hasAlignedFactualAddressReply(input, entryPoint);
|
||||
const semanticConflictWithDiscoveryTurnMeaning = hasSemanticConflictWithDiscoveryTurnMeaning(input, entryPoint);
|
||||
const matchedFactualAddressContinuationTarget = hasMatchedFactualAddressContinuationTarget(input, entryPoint);
|
||||
const matchedFactualSuggestedIntentPivotTarget = hasMatchedFactualSuggestedIntentPivotTarget(input, entryPoint);
|
||||
const fullConfirmedFactualAddressReply = hasFullConfirmedFactualAddressReply(input, entryPoint);
|
||||
const runtimeAdjustedExactReply = hasRuntimeAdjustedExactReply(input, entryPoint);
|
||||
|
||||
@@ -460,6 +489,9 @@ export function applyAssistantMcpDiscoveryResponsePolicy(
|
||||
if (matchedFactualAddressContinuationTarget) {
|
||||
pushReason(reasonCodes, "mcp_discovery_response_policy_keep_factual_address_continuation_target");
|
||||
}
|
||||
if (matchedFactualSuggestedIntentPivotTarget) {
|
||||
pushReason(reasonCodes, "mcp_discovery_response_policy_keep_factual_suggested_intent_pivot_target");
|
||||
}
|
||||
if (fullConfirmedFactualAddressReply) {
|
||||
pushReason(reasonCodes, "mcp_discovery_response_policy_keep_full_confirmed_factual_address_reply");
|
||||
}
|
||||
@@ -493,6 +525,7 @@ export function applyAssistantMcpDiscoveryResponsePolicy(
|
||||
(unsupportedBoundary || discoveryReadyChatCandidate || discoveryReadyDeepCandidate || discoveryReadyAddressCandidate) &&
|
||||
!alignedFactualAddressReply &&
|
||||
!matchedFactualAddressContinuationTarget &&
|
||||
!matchedFactualSuggestedIntentPivotTarget &&
|
||||
!fullConfirmedFactualAddressReply &&
|
||||
!runtimeAdjustedExactReply &&
|
||||
!(deterministicBroadBusinessEvaluationReply && candidate.candidate_status === "clarification_candidate") &&
|
||||
|
||||
@@ -47,6 +47,99 @@ export function createAssistantTransitionPolicy(deps) {
|
||||
return deps.compactWhitespace(deps.repairAddressMojibake(String(value ?? "")).toLowerCase()).replace(/ё/g, "е");
|
||||
}
|
||||
|
||||
function hasBankOperationsPivotCue(text) {
|
||||
const normalized = normalizeFollowupText(text);
|
||||
if (!normalized) {
|
||||
return false;
|
||||
}
|
||||
return /(?:платеж|платёж|банк|банковск|операц|выписк|поступлен|списан)/iu.test(
|
||||
normalized
|
||||
);
|
||||
}
|
||||
|
||||
function hasContractsPivotCue(text) {
|
||||
const normalized = normalizeFollowupText(text);
|
||||
if (!normalized) {
|
||||
return false;
|
||||
}
|
||||
return /(?:РґРѕРіРѕРІРѕСЂ)/iu.test(normalized);
|
||||
}
|
||||
|
||||
function hasDocumentsPivotCue(text) {
|
||||
const normalized = normalizeFollowupText(text);
|
||||
if (!normalized) {
|
||||
return false;
|
||||
}
|
||||
return /(?:документ|счет|счёт|накладн|акт)/iu.test(normalized);
|
||||
}
|
||||
|
||||
function hasReadableBankOperationsPivotCue(text) {
|
||||
const normalized = normalizeFollowupText(text).replace(/ё/g, "е");
|
||||
if (!normalized) {
|
||||
return false;
|
||||
}
|
||||
return /(?:платеж|оплат|банк|банковск|операц|поступлен|списан|выписк|перевод|payment|bank|transaction)/iu.test(
|
||||
normalized
|
||||
);
|
||||
}
|
||||
|
||||
function hasReadableContractsPivotCue(text) {
|
||||
const normalized = normalizeFollowupText(text).replace(/ё/g, "е");
|
||||
if (!normalized) {
|
||||
return false;
|
||||
}
|
||||
return /(?:договор|контракт|соглашен|contract|agreement)/iu.test(normalized);
|
||||
}
|
||||
|
||||
function hasReadableDocumentsPivotCue(text) {
|
||||
const normalized = normalizeFollowupText(text).replace(/ё/g, "е");
|
||||
if (!normalized) {
|
||||
return false;
|
||||
}
|
||||
return /(?:документ|счет|счет-фактур|накладн|акт|реализац|document|invoice|receipt)/iu.test(normalized);
|
||||
}
|
||||
|
||||
function selectSuggestedIntentByPivotCue(suggestedIntents, userMessage, alternateMessage = null) {
|
||||
if (!Array.isArray(suggestedIntents) || suggestedIntents.length === 0) {
|
||||
return null;
|
||||
}
|
||||
const samples = [userMessage, alternateMessage].filter((item) => deps.toNonEmptyString(item));
|
||||
if (samples.length === 0) {
|
||||
return null;
|
||||
}
|
||||
if (
|
||||
suggestedIntents.includes("bank_operations_by_counterparty") &&
|
||||
samples.some((sample) => hasBankOperationsPivotCue(sample) || hasReadableBankOperationsPivotCue(sample))
|
||||
) {
|
||||
return "bank_operations_by_counterparty";
|
||||
}
|
||||
if (
|
||||
suggestedIntents.includes("bank_operations_by_contract") &&
|
||||
samples.some((sample) => hasBankOperationsPivotCue(sample) || hasReadableBankOperationsPivotCue(sample))
|
||||
) {
|
||||
return "bank_operations_by_contract";
|
||||
}
|
||||
if (
|
||||
suggestedIntents.includes("list_contracts_by_counterparty") &&
|
||||
samples.some((sample) => hasContractsPivotCue(sample) || hasReadableContractsPivotCue(sample))
|
||||
) {
|
||||
return "list_contracts_by_counterparty";
|
||||
}
|
||||
if (
|
||||
suggestedIntents.includes("list_documents_by_counterparty") &&
|
||||
samples.some((sample) => hasDocumentsPivotCue(sample) || hasReadableDocumentsPivotCue(sample))
|
||||
) {
|
||||
return "list_documents_by_counterparty";
|
||||
}
|
||||
if (
|
||||
suggestedIntents.includes("list_documents_by_contract") &&
|
||||
samples.some((sample) => hasDocumentsPivotCue(sample) || hasReadableDocumentsPivotCue(sample))
|
||||
) {
|
||||
return "list_documents_by_contract";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function hasSelectedObjectInventoryScopeSignal(text) {
|
||||
const normalized = normalizeFollowupText(text);
|
||||
if (!normalized) {
|
||||
@@ -478,6 +571,15 @@ export function createAssistantTransitionPolicy(deps) {
|
||||
previousAddressDebug ??
|
||||
(hasOrganizationClarificationContinuation ? lastOrganizationClarificationDebug : null);
|
||||
const followupOffer = carryoverSourceDebug ? deps.buildAddressFollowupOffer(carryoverSourceDebug) : null;
|
||||
const suggestedIntentFromPivotCue = selectSuggestedIntentByPivotCue(
|
||||
Array.isArray(followupOffer?.suggested_intents) ? followupOffer.suggested_intents : [],
|
||||
userMessage,
|
||||
alternateMessage
|
||||
);
|
||||
const hasSuggestedIntentPivotSignal =
|
||||
Boolean(previousAddressDebug) &&
|
||||
Boolean(followupOffer?.enabled) &&
|
||||
Boolean(suggestedIntentFromPivotCue);
|
||||
const hasImplicitContinuationSignal =
|
||||
Boolean(previousAddressDebug) &&
|
||||
Boolean(followupOffer?.enabled) &&
|
||||
@@ -588,6 +690,7 @@ export function createAssistantTransitionPolicy(deps) {
|
||||
hasAlternateIndexReferenceSignal ||
|
||||
hasOrganizationClarificationContinuation ||
|
||||
hasImplicitContinuationSignal ||
|
||||
hasSuggestedIntentPivotSignal ||
|
||||
inventoryShortFollowupPrimary ||
|
||||
inventoryShortFollowupAlternate ||
|
||||
hasInventoryRootTemporalFollowupPrimary ||
|
||||
@@ -809,9 +912,9 @@ export function createAssistantTransitionPolicy(deps) {
|
||||
if (debtRoleSwapIntent) {
|
||||
previousIntent = debtRoleSwapIntent;
|
||||
}
|
||||
if (hasImplicitContinuationSignal) {
|
||||
if (hasImplicitContinuationSignal || hasSuggestedIntentPivotSignal) {
|
||||
const suggestedIntent = Array.isArray(followupOffer?.suggested_intents)
|
||||
? deps.toNonEmptyString(followupOffer.suggested_intents[0])
|
||||
? suggestedIntentFromPivotCue ?? deps.toNonEmptyString(followupOffer.suggested_intents[0])
|
||||
: null;
|
||||
const keepPreviousIntent = shouldKeepPreviousIntentForShortCounterpartyRetargetV2(userMessage, sourceIntent);
|
||||
if (suggestedIntent && !keepPreviousIntent) {
|
||||
@@ -1124,7 +1227,8 @@ export function createAssistantTransitionPolicy(deps) {
|
||||
previousAddressAnchor: previousAnchor,
|
||||
previousSourceIntent: sourceIntent,
|
||||
followupSelectionMode,
|
||||
hasImplicitContinuationSignal
|
||||
hasImplicitContinuationSignal,
|
||||
hasSuggestedIntentPivotSignal
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1151,6 +1255,7 @@ export function createAssistantTransitionPolicy(deps) {
|
||||
? carryoverTargetIntent ?? rootIntent ?? explicitIntent ?? null
|
||||
: carryoverTargetIntent ?? explicitIntent ?? deps.toNonEmptyString(carryoverMeta?.previousAddressIntent) ?? null;
|
||||
const hasImplicitContinuationSignal = Boolean(carryoverMeta?.hasImplicitContinuationSignal);
|
||||
const hasSuggestedIntentPivotSignal = Boolean(carryoverMeta?.hasSuggestedIntentPivotSignal);
|
||||
const rewrittenByPredecompose =
|
||||
deps.compactWhitespace(sourceMessage.toLowerCase()) !== deps.compactWhitespace(canonicalMessage.toLowerCase());
|
||||
const hasExplicitIntent = Boolean(explicitIntent);
|
||||
@@ -1166,6 +1271,9 @@ export function createAssistantTransitionPolicy(deps) {
|
||||
if (hasImplicitContinuationSignal) {
|
||||
reasons.push("implicit_continuation_by_llm");
|
||||
}
|
||||
if (hasSuggestedIntentPivotSignal) {
|
||||
reasons.push("suggested_intent_followup_pivot");
|
||||
}
|
||||
if (rewrittenByPredecompose) {
|
||||
reasons.push("effective_message_rewritten_by_predecompose");
|
||||
}
|
||||
@@ -1190,7 +1298,8 @@ export function createAssistantTransitionPolicy(deps) {
|
||||
intent_selection_mode: selectionMode,
|
||||
anchor_type: carryoverMeta?.followupContext?.previous_anchor_type ?? null,
|
||||
anchor_value: carryoverMeta?.followupContext?.previous_anchor_value ?? null,
|
||||
implicit_continuation_signal: hasImplicitContinuationSignal
|
||||
implicit_continuation_signal: hasImplicitContinuationSignal,
|
||||
suggested_intent_pivot_signal: hasSuggestedIntentPivotSignal
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user