Закрепить phase83 planner-brain replay ассистента
This commit is contained in:
@@ -224,7 +224,7 @@ function valueFlowZeroResultConfirmedLine(pilot) {
|
||||
const period = explicitDateScope(pilot);
|
||||
const organizationPart = organization ? ` по организации ${organization}` : "";
|
||||
const periodPart = period ? ` за период ${period}` : " в проверенном окне";
|
||||
return `В проверенном срезе 1С по контрагенту ${counterparty}${organizationPart}${periodPart} ${valueFlowDirectionLabelRu(pilot)} не найдено.`;
|
||||
return `В проверенном срезе 1С по контрагенту ${counterparty}${organizationPart}${periodPart}: 0 руб.; ${valueFlowDirectionLabelRu(pilot)} не найдено.`;
|
||||
}
|
||||
function valueFlowZeroResultUnknownLine(pilot) {
|
||||
if (!hasExecutedZeroValueFlowRows(pilot)) {
|
||||
|
||||
+37
-4
@@ -123,6 +123,14 @@ function hasBusinessOverviewDirectMoneyAnswerHint(input) {
|
||||
}
|
||||
return /(?:\u0441\u043a\u043e\u043b\u044c\u043a\u043e|\u0441\u043a\u043e\u043a\w*|how\s+much)[\s\S]{0,120}(?:\u0437\u0430\u0440\u0430\u0431\u043e\u0442|\u0432\u044b\u0440\u0443\u0447|\u0434\u0435\u043d\p{L}*|\u043f\u043e\u043b\u0443\u0447|\u043f\u043e\u0441\u0442\u0443\u043f\p{L}*)|(?:\u0437\u0430\u0440\u0430\u0431\u043e\u0442|\u0432\u044b\u0440\u0443\u0447)[\s\S]{0,120}(?:\u0441\u043a\u043e\u043b\u044c\u043a\u043e|\u0441\u043a\u043e\u043a\w*|\u0432\u0441\u0435\u0433\u043e|\u0432\u043e\u043e\u0431\u0449\u0435|(?:19|20)\d{2}|all\s+time)|(?:\u043a\u0430\u043a\u043e\u0439|\u043a\u0430\u043a\u0430\u044f|\u043a\u0430\u043a\u0438\u0435|which|what)[\s\S]{0,80}(?:\u0441\u0430\u043c\p{L}*|top|best|most)[\s\S]{0,80}(?:\u0434\u043e\u0445\u043e\u0434\u043d|\u0432\u044b\u0440\u0443\u0447|\u043e\u0431\u043e\u0440\u043e\u0442|revenue|turnover)[\s\S]{0,40}(?:\u0433\u043e\u0434|year)/iu.test(text);
|
||||
}
|
||||
function hasIncomingVsOutgoingComparisonHint(rawUtterance) {
|
||||
if (!rawUtterance) {
|
||||
return false;
|
||||
}
|
||||
const mentionsBothDirections = /(?:\u0432\u0445\u043e\u0434\p{L}*[\s\S]{0,100}\u0438(?:\u043b\u0438)?\s+\u0438\u0441\u0445\u043e\u0434\p{L}*|\u0438\u0441\u0445\u043e\u0434\p{L}*[\s\S]{0,100}\u0438(?:\u043b\u0438)?\s+\u0432\u0445\u043e\u0434\p{L}*|incoming[\s\S]{0,100}outgoing|outgoing[\s\S]{0,100}incoming)/iu.test(rawUtterance);
|
||||
const asksComparison = /(?:\u0447\u0442\u043e[\s\S]{0,40}\u0431\u043e\u043b\p{L}*|\u0431\u043e\u043b\p{L}*[\s\S]{0,40}\u0447\u0442\u043e|\u043f\u0440\u0435\u0432\u044b\p{L}*|\u043f\u043b\u044e\u0441|\u043c\u0438\u043d\u0443\u0441|\u0441\u0440\u0430\u0432\u043d\p{L}*|which[\s\S]{0,40}(?:more|larger|higher|bigger)|what[\s\S]{0,40}(?:more|larger|higher|bigger)|(?:more|larger|higher|bigger)[\s\S]{0,40}(?:incoming|outgoing))/iu.test(rawUtterance);
|
||||
return mentionsBothDirections && asksComparison;
|
||||
}
|
||||
function timeScopeNeedFor(input) {
|
||||
if (input.explicitDateScope) {
|
||||
return "explicit_period";
|
||||
@@ -420,7 +428,7 @@ function buildAssistantMcpDiscoveryDataNeedGraph(input) {
|
||||
const explicitOrganizationScope = toNonEmptyString(turnMeaning?.explicit_organization_scope);
|
||||
const metadataScopeHint = toNonEmptyString(turnMeaning?.metadata_scope_hint);
|
||||
const subjectResolutionOptional = turnMeaning?.subject_resolution_optional === true;
|
||||
const subjectCandidates = (turnMeaning?.explicit_entity_candidates ?? [])
|
||||
const rawSubjectCandidates = (turnMeaning?.explicit_entity_candidates ?? [])
|
||||
.map((item) => toNonEmptyString(item))
|
||||
.filter((item) => Boolean(item));
|
||||
const initialBusinessFactFamily = businessFactFamilyFor({
|
||||
@@ -434,10 +442,26 @@ function buildAssistantMcpDiscoveryDataNeedGraph(input) {
|
||||
const oneSidedBusinessOverviewValueFlowOverride = initialBusinessFactFamily === "business_overview" &&
|
||||
Boolean(oneSidedValueAction) &&
|
||||
!detailedBusinessOverviewMoneyBreakdownHint;
|
||||
const action = oneSidedBusinessOverviewValueFlowOverride ? oneSidedValueAction : rawAction;
|
||||
const businessFactFamily = oneSidedBusinessOverviewValueFlowOverride ? "value_flow" : initialBusinessFactFamily;
|
||||
const bidirectionalBusinessOverviewValueFlowOverride = initialBusinessFactFamily === "business_overview" && hasIncomingVsOutgoingComparisonHint(rawQuestionSignal);
|
||||
const oneSidedValueFlowActionOverride = initialBusinessFactFamily === "value_flow" &&
|
||||
Boolean(oneSidedValueAction) &&
|
||||
(rawAction === "counterparty_value_or_turnover" || rawAction === "counterparty_value");
|
||||
const action = bidirectionalBusinessOverviewValueFlowOverride
|
||||
? "net_value_flow"
|
||||
: oneSidedBusinessOverviewValueFlowOverride || oneSidedValueFlowActionOverride
|
||||
? oneSidedValueAction
|
||||
: rawAction;
|
||||
const businessFactFamily = oneSidedBusinessOverviewValueFlowOverride || bidirectionalBusinessOverviewValueFlowOverride
|
||||
? "value_flow"
|
||||
: initialBusinessFactFamily;
|
||||
const aggregationNeed = aggregationNeedFor(aggregationAxis);
|
||||
const comparisonNeed = comparisonNeedFor(action);
|
||||
const organizationScopedValueComparison = businessFactFamily === "value_flow" &&
|
||||
comparisonNeed === "incoming_vs_outgoing" &&
|
||||
Boolean(explicitOrganizationScope) &&
|
||||
hasIncomingVsOutgoingComparisonHint(rawQuestionSignal);
|
||||
const subjectCandidates = organizationScopedValueComparison ? [] : rawSubjectCandidates;
|
||||
const effectiveMetadataScopeHint = organizationScopedValueComparison ? null : metadataScopeHint;
|
||||
const allTimeScopeHint = hasAllTimeScopeHint(rawUtterance);
|
||||
const subjectScopedBidirectionalAllTime = businessFactFamily === "value_flow" &&
|
||||
comparisonNeed === "incoming_vs_outgoing" &&
|
||||
@@ -556,6 +580,15 @@ function buildAssistantMcpDiscoveryDataNeedGraph(input) {
|
||||
if (oneSidedBusinessOverviewValueFlowOverride) {
|
||||
pushReason(reasonCodes, "data_need_graph_business_overview_one_sided_money_total_routed_to_value_flow");
|
||||
}
|
||||
if (bidirectionalBusinessOverviewValueFlowOverride) {
|
||||
pushReason(reasonCodes, "data_need_graph_business_overview_bidirectional_money_comparison_routed_to_value_flow");
|
||||
}
|
||||
if (organizationScopedValueComparison) {
|
||||
pushReason(reasonCodes, "data_need_graph_organization_scoped_value_comparison_ignores_stale_subject");
|
||||
}
|
||||
if (oneSidedValueFlowActionOverride) {
|
||||
pushReason(reasonCodes, "data_need_graph_value_flow_one_sided_money_total_action_normalized");
|
||||
}
|
||||
if (clarificationGaps.includes("organization")) {
|
||||
pushReason(reasonCodes, "data_need_graph_open_scope_total_needs_organization");
|
||||
}
|
||||
@@ -566,7 +599,7 @@ function buildAssistantMcpDiscoveryDataNeedGraph(input) {
|
||||
schema_version: exports.ASSISTANT_MCP_DISCOVERY_DATA_NEED_GRAPH_SCHEMA_VERSION,
|
||||
policy_owner: "assistantMcpDiscoveryDataNeedGraph",
|
||||
subject_candidates: subjectCandidates,
|
||||
metadata_scope_hint: metadataScopeHint,
|
||||
metadata_scope_hint: effectiveMetadataScopeHint,
|
||||
subject_resolution_optional: subjectResolutionOptional || undefined,
|
||||
business_fact_family: businessFactFamily,
|
||||
action_family: toNonEmptyString(action),
|
||||
|
||||
+30
-3
@@ -107,7 +107,10 @@ function scoreExplicitEntityCandidate(raw, cleaned, index) {
|
||||
return score;
|
||||
}
|
||||
function firstEntityCandidate(planner) {
|
||||
const candidates = planner.discovery_plan.turn_meaning_ref?.explicit_entity_candidates ?? [];
|
||||
const graphCandidates = planner.data_need_graph?.subject_candidates;
|
||||
const candidates = Array.isArray(graphCandidates)
|
||||
? graphCandidates
|
||||
: planner.discovery_plan.turn_meaning_ref?.explicit_entity_candidates ?? [];
|
||||
let best = null;
|
||||
for (let index = 0; index < candidates.length; index += 1) {
|
||||
const candidate = candidates[index];
|
||||
@@ -582,10 +585,32 @@ function isEntityResolutionPilotEligible(planner) {
|
||||
combined.includes("entity discovery") ||
|
||||
combined.includes("counterparty search")));
|
||||
}
|
||||
function normalizeMetadataScopeHint(value) {
|
||||
const text = toNonEmptyString(value);
|
||||
if (!text) {
|
||||
return null;
|
||||
}
|
||||
const normalized = text
|
||||
.replace(/[«»"']/gu, "")
|
||||
.replace(/\s+/g, " ")
|
||||
.trim();
|
||||
const comparable = normalized.toLowerCase().replace(/ё/g, "е");
|
||||
if (/^контрагент(?:ам|ами|ах|ов|у|а|ом|е|ы)?$/iu.test(comparable)) {
|
||||
return "контрагент";
|
||||
}
|
||||
if (/^(?:справочник\.)?контрагенты$/iu.test(comparable)) {
|
||||
return "контрагент";
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
function metadataScopeForPlanner(planner) {
|
||||
const metadataScopeHint = normalizeMetadataScopeHint(planner.discovery_plan.turn_meaning_ref?.metadata_scope_hint);
|
||||
if (metadataScopeHint) {
|
||||
return metadataScopeHint;
|
||||
}
|
||||
const entityCandidate = firstEntityCandidate(planner);
|
||||
if (entityCandidate) {
|
||||
return entityCandidate;
|
||||
return normalizeMetadataScopeHint(entityCandidate) ?? entityCandidate;
|
||||
}
|
||||
if (planner.selected_chain_id === "catalog_drilldown") {
|
||||
const surface = planner.metadata_surface_ref;
|
||||
@@ -647,7 +672,9 @@ function valueFlowPilotProfile(planner) {
|
||||
const meaning = planner.discovery_plan.turn_meaning_ref;
|
||||
const action = String(meaning?.asked_action_family ?? "").toLowerCase();
|
||||
const unsupported = String(meaning?.unsupported_but_understood_family ?? "").toLowerCase();
|
||||
const combined = `${action} ${unsupported}`;
|
||||
const graphAction = String(planner.data_need_graph?.action_family ?? "").toLowerCase();
|
||||
const graphComparison = String(planner.data_need_graph?.comparison_need ?? "").toLowerCase();
|
||||
const combined = `${action} ${unsupported} ${graphAction} ${graphComparison} ${planner.selected_chain_id}`;
|
||||
if (combined.includes("net_value_flow") ||
|
||||
combined.includes("bidirectional") ||
|
||||
combined.includes("netting") ||
|
||||
|
||||
+20
-4
@@ -614,13 +614,19 @@ function businessOverviewInventoryLine(overview) {
|
||||
].filter((item) => Boolean(item));
|
||||
return pieces.length > 0 ? `Склад: ${pieces.join(", ")}.` : null;
|
||||
}
|
||||
function bidirectionalNetLabel(direction) {
|
||||
function bidirectionalNetLabel(direction, scopeKind = "counterparty") {
|
||||
if (direction === "net_outgoing") {
|
||||
if (scopeKind === "organization") {
|
||||
return "нетто в сторону исходящих платежей";
|
||||
}
|
||||
return "нетто в сторону контрагента";
|
||||
}
|
||||
if (direction === "balanced") {
|
||||
return "нетто около нуля";
|
||||
}
|
||||
if (scopeKind === "organization") {
|
||||
return "нетто в сторону входящих платежей";
|
||||
}
|
||||
return "нетто в нашу сторону";
|
||||
}
|
||||
function buildCompactBidirectionalValueFlowReply(entryPoint, draft) {
|
||||
@@ -642,6 +648,11 @@ function buildCompactBidirectionalValueFlowReply(entryPoint, draft) {
|
||||
}
|
||||
const counterparty = toNonEmptyString(flow.counterparty);
|
||||
const organizationScope = toNonEmptyString(turnMeaning?.explicit_organization_scope);
|
||||
const scopeKind = counterparty
|
||||
? "counterparty"
|
||||
: organizationScope
|
||||
? "organization"
|
||||
: "generic";
|
||||
const subjectLead = counterparty
|
||||
? `по контрагенту ${counterparty}`
|
||||
: organizationScope
|
||||
@@ -649,9 +660,9 @@ function buildCompactBidirectionalValueFlowReply(entryPoint, draft) {
|
||||
: "по выбранному контуру";
|
||||
const period = toNonEmptyString(flow.period_scope);
|
||||
const periodText = period ? ` за период ${period}` : " в проверенном окне";
|
||||
const netLabel = bidirectionalNetLabel(flow.net_direction);
|
||||
const netLabel = bidirectionalNetLabel(flow.net_direction, scopeKind);
|
||||
const lines = [
|
||||
`Коротко: ${subjectLead}${periodText} по найденным строкам 1С получили ${incomingAmount ?? "0 руб."}, заплатили ${outgoingAmount ?? "0 руб."}; расчетное ${netLabel}: ${sentenceAmount(netAmount) ?? netAmount ?? "0 руб."}.`
|
||||
`${subjectLead}${periodText} по найденным строкам 1С получили ${incomingAmount ?? "0 руб."}, заплатили ${outgoingAmount ?? "0 руб."}; расчетное ${netLabel}: ${sentenceAmount(netAmount) ?? netAmount ?? "0 руб."}.`
|
||||
];
|
||||
const basis = [];
|
||||
if (incomingAmount) {
|
||||
@@ -661,7 +672,12 @@ function buildCompactBidirectionalValueFlowReply(entryPoint, draft) {
|
||||
basis.push("исходящие платежи");
|
||||
}
|
||||
if (basis.length > 0) {
|
||||
lines.push(`Основа: проверенные ${basis.join(" и ")} по этому контрагенту в 1С.`);
|
||||
const basisScope = scopeKind === "counterparty"
|
||||
? "по этому контрагенту"
|
||||
: scopeKind === "organization"
|
||||
? "по этой компании"
|
||||
: "по выбранному контуру";
|
||||
lines.push(`Основа: проверенные ${basis.join(" и ")} ${basisScope} в 1С.`);
|
||||
}
|
||||
if (flow.coverage_limited_by_probe_limit === true) {
|
||||
lines.push("Важно: часть проверки достигла лимита строк, поэтому это проверенный срез найденных движений, а не гарантия полного периода.");
|
||||
|
||||
@@ -247,6 +247,88 @@ function readTruthAnswerShape(input) {
|
||||
const truthAnswerPolicy = toRecordObject(input.addressRuntimeMeta?.assistant_truth_answer_policy_v1);
|
||||
return toRecordObject(truthAnswerPolicy?.answer_shape);
|
||||
}
|
||||
function hasCurrentClarificationRequiredAddressReply(input) {
|
||||
const answerShape = toNonEmptyString(input.addressRuntimeMeta?.answer_shape) ??
|
||||
toNonEmptyString(input.addressRuntimeMeta?.truth_mode) ??
|
||||
toNonEmptyString(readTruthAnswerShape(input)?.answer_shape);
|
||||
if (answerShape === "clarification_required") {
|
||||
return true;
|
||||
}
|
||||
const truthAnswerPolicy = toRecordObject(input.addressRuntimeMeta?.assistant_truth_answer_policy_v1);
|
||||
const truthGate = toRecordObject(truthAnswerPolicy?.truth_gate);
|
||||
const policyAnswerShape = toRecordObject(truthAnswerPolicy?.answer_shape);
|
||||
return (toNonEmptyString(truthGate?.truth_mode) === "clarification_required" ||
|
||||
toNonEmptyString(policyAnswerShape?.answer_shape) === "clarification_required");
|
||||
}
|
||||
function hasDiscoveryClarificationCandidatePriorityOverCurrentClarification(input, entryPoint, candidate) {
|
||||
if (!hasCurrentClarificationRequiredAddressReply(input)) {
|
||||
return false;
|
||||
}
|
||||
if (candidate.candidate_status !== "clarification_candidate") {
|
||||
return false;
|
||||
}
|
||||
if (!candidate.eligible_for_future_hot_runtime || !toNonEmptyString(candidate.reply_text)) {
|
||||
return false;
|
||||
}
|
||||
if (!isDiscoveryReadyAddressCandidate(input, entryPoint)) {
|
||||
return false;
|
||||
}
|
||||
const graph = readDiscoveryDataNeedGraph(entryPoint);
|
||||
const turnMeaning = readDiscoveryTurnMeaning(entryPoint);
|
||||
const discoveryFamily = toNonEmptyString(graph?.business_fact_family);
|
||||
const askedDomain = toNonEmptyString(turnMeaning?.asked_domain_family);
|
||||
const askedAction = toNonEmptyString(turnMeaning?.asked_action_family) ?? toNonEmptyString(graph?.action_family);
|
||||
const asksForMovements = discoveryFamily === "movement_evidence" || askedDomain === "movements" || askedAction === "list_movements";
|
||||
const truthAnswerShape = readTruthAnswerShape(input);
|
||||
const detectedIntent = toNonEmptyString(input.addressRuntimeMeta?.detected_intent);
|
||||
const selectedRecipe = toNonEmptyString(input.addressRuntimeMeta?.selected_recipe);
|
||||
const capabilityId = toNonEmptyString(input.addressRuntimeMeta?.capability_id) ??
|
||||
toNonEmptyString(input.addressRuntimeMeta?.capability_contract_id) ??
|
||||
toNonEmptyString(truthAnswerShape?.capability_contract_id);
|
||||
const missingFilters = [
|
||||
...readStringArray(input.addressRuntimeMeta?.missing_required_filters),
|
||||
...readStringArray(input.addressRuntimeMeta?.missing_anchors),
|
||||
...readStringArray(toRecordObject(input.addressRuntimeMeta?.capability_binding_contract)?.missing_anchors)
|
||||
];
|
||||
const staleInventoryItemClarification = Boolean(missingFilters.includes("item") &&
|
||||
(detectedIntent?.startsWith("inventory_") ||
|
||||
selectedRecipe?.includes("inventory_") ||
|
||||
capabilityId?.includes("inventory_")));
|
||||
return asksForMovements && staleInventoryItemClarification;
|
||||
}
|
||||
function hasGroundedValueFlowCandidatePriorityOverCurrentClarification(input, entryPoint, candidate) {
|
||||
if (!hasCurrentClarificationRequiredAddressReply(input)) {
|
||||
return false;
|
||||
}
|
||||
if (candidate.candidate_status !== "ready_for_guarded_use") {
|
||||
return false;
|
||||
}
|
||||
if (!candidate.hot_runtime_wired || !candidate.eligible_for_future_hot_runtime || !toNonEmptyString(candidate.reply_text)) {
|
||||
return false;
|
||||
}
|
||||
if (!isDiscoveryReadyAddressCandidate(input, entryPoint)) {
|
||||
return false;
|
||||
}
|
||||
const graph = readDiscoveryDataNeedGraph(entryPoint);
|
||||
const bridge = toRecordObject(entryPoint?.bridge);
|
||||
const pilot = toRecordObject(bridge?.pilot);
|
||||
const handoff = toRecordObject(bridge?.execution_handoff);
|
||||
const routeCandidate = toRecordObject(bridge?.route_candidate);
|
||||
const selectedChainId = toNonEmptyString(routeCandidate?.selected_chain_id) ??
|
||||
toNonEmptyString(bridge?.selected_chain_id) ??
|
||||
toNonEmptyString(pilot?.selected_chain_id);
|
||||
const pilotScope = toNonEmptyString(pilot?.pilot_scope);
|
||||
const actionFamily = toNonEmptyString(graph?.action_family);
|
||||
const comparisonNeed = toNonEmptyString(graph?.comparison_need);
|
||||
const valueFlowComparison = Boolean(selectedChainId === "value_flow_comparison" ||
|
||||
pilotScope === "counterparty_bidirectional_value_flow_query_movements_v1" ||
|
||||
(actionFamily === "net_value_flow" && comparisonNeed === "incoming_vs_outgoing"));
|
||||
const mcpExecutionPerformed = handoff?.mcp_execution_performed === true || pilot?.mcp_execution_performed === true;
|
||||
const guardedBusinessAnswerAllowed = bridge?.user_facing_response_allowed === true &&
|
||||
bridge?.business_fact_answer_allowed === true &&
|
||||
(handoff?.can_use_guarded_response === true || toNonEmptyString(bridge?.bridge_status) === "answer_draft_ready");
|
||||
return valueFlowComparison && mcpExecutionPerformed && guardedBusinessAnswerAllowed;
|
||||
}
|
||||
function hasEffectivelyFactualAddressReply(input) {
|
||||
if (toNonEmptyString(input.currentReplyType) === "factual") {
|
||||
return true;
|
||||
@@ -719,6 +801,12 @@ function applyAssistantMcpDiscoveryResponsePolicy(input) {
|
||||
const metadataDiscoveryPriority = hasMetadataDiscoveryPriority(input, entryPoint);
|
||||
const valueFlowActionConflictWithDiscoveryTurnMeaning = hasValueFlowActionConflictWithDiscoveryTurnMeaning(input, entryPoint);
|
||||
const evidenceLaneConflictWithDiscoveryTurnMeaning = hasEvidenceLaneConflictWithDiscoveryTurnMeaning(input, entryPoint);
|
||||
const currentClarificationRequiredAddressReply = hasCurrentClarificationRequiredAddressReply(input);
|
||||
const discoveryClarificationCandidatePriority = hasDiscoveryClarificationCandidatePriorityOverCurrentClarification(input, entryPoint, candidate);
|
||||
const groundedValueFlowCandidatePriority = hasGroundedValueFlowCandidatePriorityOverCurrentClarification(input, entryPoint, candidate);
|
||||
const currentClarificationProtectsCurrentReply = currentClarificationRequiredAddressReply &&
|
||||
!discoveryClarificationCandidatePriority &&
|
||||
!groundedValueFlowCandidatePriority;
|
||||
const exactBankOperationsProtectsCurrent = exactBankOperationsAddressReply &&
|
||||
!semanticConflictWithDiscoveryTurnMeaning &&
|
||||
!valueFlowActionConflictWithDiscoveryTurnMeaning;
|
||||
@@ -752,6 +840,15 @@ function applyAssistantMcpDiscoveryResponsePolicy(input) {
|
||||
if (evidenceLaneConflictWithDiscoveryTurnMeaning) {
|
||||
pushReason(reasonCodes, "mcp_discovery_response_policy_evidence_lane_conflict_allows_candidate_override");
|
||||
}
|
||||
if (currentClarificationProtectsCurrentReply) {
|
||||
pushReason(reasonCodes, "mcp_discovery_response_policy_keep_current_clarification_required_reply");
|
||||
}
|
||||
if (discoveryClarificationCandidatePriority) {
|
||||
pushReason(reasonCodes, "mcp_discovery_response_policy_clarification_candidate_priority_over_stale_address_clarification");
|
||||
}
|
||||
if (groundedValueFlowCandidatePriority) {
|
||||
pushReason(reasonCodes, "mcp_discovery_response_policy_grounded_value_flow_candidate_priority_over_current_clarification");
|
||||
}
|
||||
if (openScopeValueFlowDiscoveryPriority) {
|
||||
pushReason(reasonCodes, "mcp_discovery_response_policy_open_scope_value_flow_candidate_priority");
|
||||
}
|
||||
@@ -827,6 +924,7 @@ function applyAssistantMcpDiscoveryResponsePolicy(input) {
|
||||
!exactDocumentListAddressReply &&
|
||||
!inventoryMarginRankingAddressReply &&
|
||||
!exactInventoryChainProtectsCurrent &&
|
||||
!currentClarificationProtectsCurrentReply &&
|
||||
!(deterministicBroadBusinessEvaluationReply && candidate.candidate_status === "clarification_candidate") &&
|
||||
ALLOWED_CANDIDATE_STATUSES.has(candidate.candidate_status) &&
|
||||
candidate.eligible_for_future_hot_runtime &&
|
||||
|
||||
+26
-1
@@ -60,10 +60,25 @@ function isReferentialEntityPlaceholder(value) {
|
||||
"этом"
|
||||
]).has((0, addressTextRepair_1.normalizeRussianComparableText)(value));
|
||||
}
|
||||
function isNegativeCounterpartyScopePlaceholder(value) {
|
||||
if (!value) {
|
||||
return false;
|
||||
}
|
||||
const text = compactLower((0, addressTextRepair_1.repairAddressMojibakeText)(value));
|
||||
if (!text) {
|
||||
return false;
|
||||
}
|
||||
return (/(?:без\s+(?:привязк\p{L}*|конкретн\p{L}*)\s+к\s+контрагент\p{L}*|без\s+контрагент\p{L}*)/iu.test(text) ||
|
||||
/(?:одн\p{L}*\s+организац\p{L}*\s+без\s+привязк\p{L}*)/iu.test(text) ||
|
||||
/(?:organization\s+without\s+(?:counterparty|specific\s+counterparty))/iu.test(text));
|
||||
}
|
||||
function isReferentialOrganizationPlaceholder(value) {
|
||||
if (!value) {
|
||||
return false;
|
||||
}
|
||||
if (isNegativeCounterpartyScopePlaceholder(value)) {
|
||||
return true;
|
||||
}
|
||||
return new Set([
|
||||
"эта организация",
|
||||
"этой организации",
|
||||
@@ -129,6 +144,12 @@ function isGarbageSemanticAnchorCandidate(value) {
|
||||
"этими",
|
||||
"итогу",
|
||||
"итогам",
|
||||
"одной",
|
||||
"одному",
|
||||
"одним",
|
||||
"одна",
|
||||
"один",
|
||||
"одно",
|
||||
"всему",
|
||||
"всей",
|
||||
"всем",
|
||||
@@ -168,7 +189,8 @@ function isGarbageSemanticAnchorCandidate(value) {
|
||||
]).has(compact)) {
|
||||
return true;
|
||||
}
|
||||
if (/^(?:по\s+)?(?:этим|этими)\s+данн\p{L}*$/iu.test(text) ||
|
||||
if (isNegativeCounterpartyScopePlaceholder(text) ||
|
||||
/^(?:по\s+)?(?:этим|этими)\s+данн\p{L}*$/iu.test(text) ||
|
||||
/^(?:и\s+)?кто\s+(?:главн\p{L}*|основн\p{L}*|крупн\p{L}*)\s+(?:клиент|покупател|поставщик|контрагент)(?:\s+в)?$/iu.test(text) ||
|
||||
/^(?:и\s+)?(?:главн\p{L}*|основн\p{L}*|крупн\p{L}*)\s+(?:клиент|покупател|поставщик|контрагент)(?:\s+в)?$/iu.test(text) ||
|
||||
/^(?:или\s+)?(?:обычн\p{L}*\s+)?(?:клиент|поставщик|покупател\p{L}*|заказчик|контрагент)(?:\s+или\s+(?:клиент|поставщик|покупател\p{L}*|заказчик|контрагент))?$/iu.test(text) ||
|
||||
@@ -898,6 +920,9 @@ function normalizeLooseOrganizationAlias(value) {
|
||||
if (!text) {
|
||||
return null;
|
||||
}
|
||||
if (isNegativeCounterpartyScopePlaceholder(text)) {
|
||||
return null;
|
||||
}
|
||||
const normalized = text
|
||||
.replace(/^[«"'“”]+|[»"'“”]+$/gu, "")
|
||||
.replace(/\s+/g, " ")
|
||||
|
||||
Reference in New Issue
Block a user