ARCH: стабилизировать continuity и защитить exact-ответы от discovery

This commit is contained in:
2026-04-21 18:43:05 +03:00
parent b542b65b81
commit 429bd3d8ec
8 changed files with 603 additions and 18 deletions
@@ -89,6 +89,56 @@ function isDiscoveryReadyAddressCandidate(input, entryPoint) {
turnInput?.should_run_discovery === true &&
(source === "address_lane" || source === "address_exact" || source === "address_query_runtime_v1"));
}
function hasAlignedFactualAddressReply(input, entryPoint) {
if (!isDiscoveryReadyAddressCandidate(input, entryPoint)) {
return false;
}
if (toNonEmptyString(input.currentReplyType) !== "factual") {
return false;
}
const detectedIntent = toNonEmptyString(input.addressRuntimeMeta?.detected_intent);
const turnInput = toRecordObject(entryPoint?.turn_input);
const turnMeaning = toRecordObject(turnInput?.turn_meaning_ref);
const askedDomain = toNonEmptyString(turnMeaning?.asked_domain_family);
const askedAction = toNonEmptyString(turnMeaning?.asked_action_family);
if (detectedIntent === "counterparty_activity_lifecycle") {
return askedDomain === "counterparty_lifecycle" || askedAction === "activity_duration";
}
if (detectedIntent === "supplier_payouts_profile") {
return askedDomain === "counterparty_value" && askedAction === "payout";
}
if (detectedIntent === "customer_revenue_and_payments") {
return askedDomain === "counterparty_value" && askedAction === "turnover";
}
return false;
}
function hasMatchedFactualAddressContinuationTarget(input) {
if (toNonEmptyString(input.currentReplyType) !== "factual") {
return false;
}
const detectedIntent = toNonEmptyString(input.addressRuntimeMeta?.detected_intent);
const dialogContinuationContract = toRecordObject(input.addressRuntimeMeta?.dialogContinuationContract);
const targetIntent = toNonEmptyString(dialogContinuationContract?.target_intent);
return Boolean(detectedIntent && targetIntent && detectedIntent === targetIntent);
}
function hasFullConfirmedFactualAddressReply(input, entryPoint) {
if (!isDiscoveryReadyAddressCandidate(input, entryPoint)) {
return false;
}
if (toNonEmptyString(input.currentReplyType) !== "factual") {
return false;
}
const truthGateStatus = toNonEmptyString(input.addressRuntimeMeta?.truth_gate_contract_status);
if (truthGateStatus === "full_confirmed") {
return true;
}
const truthAnswerPolicy = toRecordObject(input.addressRuntimeMeta?.assistant_truth_answer_policy_v1);
const truthGate = toRecordObject(truthAnswerPolicy?.truth_gate);
const sourceTruthGateStatus = toNonEmptyString(truthGate?.source_truth_gate_status);
const coverageStatus = toNonEmptyString(truthGate?.coverage_status);
const groundingStatus = toNonEmptyString(truthGate?.grounding_status);
return sourceTruthGateStatus === "full_confirmed" || (coverageStatus === "full" && groundingStatus === "grounded");
}
function applyAssistantMcpDiscoveryResponsePolicy(input) {
const currentReply = String(input.currentReply ?? "");
const currentReplySource = toNonEmptyString(input.currentReplySource) ?? toNonEmptyString(input.livingChatSource) ?? "unknown";
@@ -99,6 +149,9 @@ function applyAssistantMcpDiscoveryResponsePolicy(input) {
const discoveryReadyChatCandidate = isDiscoveryReadyChatCandidate(input, entryPoint);
const discoveryReadyDeepCandidate = isDiscoveryReadyDeepCandidate(input, entryPoint);
const discoveryReadyAddressCandidate = isDiscoveryReadyAddressCandidate(input, entryPoint);
const alignedFactualAddressReply = hasAlignedFactualAddressReply(input, entryPoint);
const matchedFactualAddressContinuationTarget = hasMatchedFactualAddressContinuationTarget(input);
const fullConfirmedFactualAddressReply = hasFullConfirmedFactualAddressReply(input, entryPoint);
if (!entryPoint) {
pushReason(reasonCodes, "mcp_discovery_response_policy_no_entry_point");
}
@@ -114,6 +167,15 @@ function applyAssistantMcpDiscoveryResponsePolicy(input) {
if (!discoveryReadyAddressCandidate) {
pushReason(reasonCodes, "mcp_discovery_response_policy_not_discovery_ready_address_candidate");
}
if (alignedFactualAddressReply) {
pushReason(reasonCodes, "mcp_discovery_response_policy_keep_aligned_factual_address_reply");
}
if (matchedFactualAddressContinuationTarget) {
pushReason(reasonCodes, "mcp_discovery_response_policy_keep_factual_address_continuation_target");
}
if (fullConfirmedFactualAddressReply) {
pushReason(reasonCodes, "mcp_discovery_response_policy_keep_full_confirmed_factual_address_reply");
}
if (!ALLOWED_CANDIDATE_STATUSES.has(candidate.candidate_status)) {
pushReason(reasonCodes, "mcp_discovery_response_policy_candidate_status_not_allowed");
}
@@ -128,6 +190,9 @@ function applyAssistantMcpDiscoveryResponsePolicy(input) {
}
const canApply = Boolean(entryPoint) &&
(unsupportedBoundary || discoveryReadyChatCandidate || discoveryReadyDeepCandidate || discoveryReadyAddressCandidate) &&
!alignedFactualAddressReply &&
!matchedFactualAddressContinuationTarget &&
!fullConfirmedFactualAddressReply &&
ALLOWED_CANDIDATE_STATUSES.has(candidate.candidate_status) &&
candidate.eligible_for_future_hot_runtime &&
Boolean(toNonEmptyString(candidate.reply_text)) &&
@@ -7,7 +7,10 @@ const SUPPORTED_ADDRESS_INTENTS = new Set([
"payables_confirmed_as_of_date",
"list_documents_by_counterparty",
"customer_revenue_and_payments",
"inventory_on_hand_as_of_date"
"inventory_on_hand_as_of_date",
"vat_liability_confirmed_for_tax_period",
"vat_payable_confirmed_as_of_date",
"vat_payable_forecast"
]);
function fallbackCompactWhitespace(value) {
return String(value ?? "").replace(/\s+/g, " ").trim();
@@ -85,8 +88,23 @@ function detectCounterpartyTurnoverFamily(text) {
"\u0434\u043e\u0445\u043e\u0434",
"\u0431\u044b\u043b",
"\u0431\u044b\u043b\u0430",
"\u0432\u0440\u0435\u043c\u044f",
"\u0432\u0440\u0435\u043c\u0435\u043d\u0438",
"\u0433\u043e\u0434",
"\u0433\u043e\u0434\u0430",
"\u043f\u0435\u0440\u0438\u043e\u0434",
"\u043f\u0435\u0440\u0438\u043e\u0434\u0430",
"\u043c\u0435\u0441\u044f\u0446",
"\u043c\u0435\u0441\u044f\u0446\u0430",
"\u043a\u0432\u0430\u0440\u0442\u0430\u043b",
"\u043a\u0432\u0430\u0440\u0442\u0430\u043b\u0430",
"turnover",
"revenue"
"revenue",
"time",
"year",
"period",
"month",
"quarter"
]);
const entity = rawEntity && !ignored.has(rawEntity) ? rawEntity : null;
return {
@@ -136,22 +154,30 @@ function createAssistantTurnMeaningPolicy(deps = {}) {
? "receivables"
: explicitIntentCandidate?.startsWith("payables_")
? "payables"
: explicitIntentCandidate?.startsWith("inventory_")
? "inventory"
: explicitIntentCandidate?.includes("counterparty")
? "counterparty"
: counterpartyTurnover?.family
: explicitIntentCandidate?.startsWith("vat_")
? "vat"
: explicitIntentCandidate?.startsWith("inventory_")
? "inventory"
: explicitIntentCandidate?.includes("counterparty")
? "counterparty"
: null;
: counterpartyTurnover?.family
? "counterparty"
: null;
const askedActionFamily = explicitIntentCandidate === "receivables_confirmed_as_of_date" ||
explicitIntentCandidate === "payables_confirmed_as_of_date" ||
explicitIntentCandidate === "inventory_on_hand_as_of_date"
? "confirmed_snapshot"
: explicitIntentCandidate === "list_documents_by_counterparty"
? "list_documents"
: counterpartyTurnover?.family
? "counterparty_value_or_turnover"
: null;
: explicitIntentCandidate === "vat_liability_confirmed_for_tax_period"
? "confirmed_tax_period"
: explicitIntentCandidate === "vat_payable_confirmed_as_of_date"
? "confirmed_snapshot"
: explicitIntentCandidate === "vat_payable_forecast"
? "forecast"
: explicitIntentCandidate === "list_documents_by_counterparty"
? "list_documents"
: counterpartyTurnover?.family
? "counterparty_value_or_turnover"
: null;
const staleReplayForbidden = Boolean(unsupportedFamily || (counterpartyTurnover?.entity && !explicitIntentCandidate));
return {
schema_version: "assistant_turn_meaning_v1",