ARCH: усилить metadata ambiguity choice sets в lane arbitration

This commit is contained in:
2026-04-22 09:45:49 +03:00
parent d9454fcdef
commit c328c52c9b
6 changed files with 282 additions and 17 deletions
@@ -192,6 +192,17 @@ export function readAssistantMcpDiscoveryMetadataAmbiguityDetected(
return readAssistantMcpDiscoveryDerivedMetadataSurface(debug)?.ambiguity_detected === true;
}
export function readAssistantMcpDiscoveryMetadataAmbiguityEntitySets(
debug: Record<string, unknown> | null,
toNonEmptyString: (value: unknown) => string | null = fallbackToNonEmptyString
): string[] {
const values = readAssistantMcpDiscoveryDerivedMetadataSurface(debug)?.ambiguity_entity_sets;
if (!Array.isArray(values)) {
return [];
}
return values.map((item) => toNonEmptyString(item)).filter((item): item is string => Boolean(item));
}
function mapAssistantMcpDiscoveryPilotScopeToAddressIntent(
pilotScope: string | null,
actionFamily: string | null
@@ -265,6 +265,7 @@ function collectFollowupDiscoverySeed(followupContext: Record<string, unknown> |
metadataRouteFamily: string | null;
metadataSelectedEntitySet: string | null;
metadataAmbiguityDetected: boolean;
metadataAmbiguityEntitySets: string[];
} {
const previousFilters = toRecordObject(followupContext?.previous_filters);
const rootFilters = toRecordObject(followupContext?.root_filters);
@@ -302,10 +303,29 @@ function collectFollowupDiscoverySeed(followupContext: Record<string, unknown> |
dateScope,
metadataRouteFamily: toNonEmptyString(followupContext?.previous_discovery_metadata_route_family),
metadataSelectedEntitySet: toNonEmptyString(followupContext?.previous_discovery_metadata_selected_entity_set),
metadataAmbiguityDetected: followupContext?.previous_discovery_metadata_ambiguity_detected === true
metadataAmbiguityDetected: followupContext?.previous_discovery_metadata_ambiguity_detected === true,
metadataAmbiguityEntitySets: collectEntityCandidates(followupContext?.previous_discovery_metadata_ambiguity_entity_sets)
};
}
function metadataEntitySetsSuggestDocumentLane(values: string[]): boolean {
return values.some((value) => /(?:документ|document|invoice|waybill|накладн|счет[- ]?фактур|акт)/iu.test(value));
}
function metadataEntitySetsSuggestMovementLane(values: string[]): boolean {
return values.some((value) =>
/(?:регистр|register|movement|движени|операц|проводк|bank)/iu.test(value)
);
}
function metadataAmbiguityCollapsesToDocumentLane(values: string[]): boolean {
return values.length > 0 && metadataEntitySetsSuggestDocumentLane(values) && !metadataEntitySetsSuggestMovementLane(values);
}
function metadataAmbiguityCollapsesToMovementLane(values: string[]): boolean {
return values.length > 0 && metadataEntitySetsSuggestMovementLane(values) && !metadataEntitySetsSuggestDocumentLane(values);
}
function hasLifecycleSignal(text: string): boolean {
return /(?:сколько\s+лет|как\s+давно|давно\s+ли|возраст|перв(?:ая|ый)\s+актив|когда\s+начал|когда\s+появ|lifecycle|activity\s+duration|business\s+age|how\s+long)/iu.test(
text
@@ -520,6 +540,8 @@ export function buildAssistantMcpDiscoveryTurnInput(
const metadataAmbiguityResolvedDocumentFollowupApplicable = Boolean(
followupSeed.pilotScope === "metadata_inspection_v1" &&
followupSeed.metadataAmbiguityDetected &&
(followupSeed.metadataAmbiguityEntitySets.length === 0 ||
metadataEntitySetsSuggestDocumentLane(followupSeed.metadataAmbiguityEntitySets)) &&
followupSeed.counterparty &&
!rawLifecycleSignal &&
!rawValueFlowSignal &&
@@ -536,6 +558,8 @@ export function buildAssistantMcpDiscoveryTurnInput(
const metadataAmbiguityResolvedMovementFollowupApplicable = Boolean(
followupSeed.pilotScope === "metadata_inspection_v1" &&
followupSeed.metadataAmbiguityDetected &&
(followupSeed.metadataAmbiguityEntitySets.length === 0 ||
metadataEntitySetsSuggestMovementLane(followupSeed.metadataAmbiguityEntitySets)) &&
followupSeed.counterparty &&
!rawLifecycleSignal &&
metadataMovementHintSignal
@@ -553,14 +577,40 @@ export function buildAssistantMcpDiscoveryTurnInput(
!metadataMovementHintSignal &&
hasMetadataDownstreamContinuationSignal(rawText)
);
const metadataAmbiguityCollapsedDocumentLaneContinuationApplicable = Boolean(
followupSeed.pilotScope === "metadata_inspection_v1" &&
followupSeed.metadataAmbiguityDetected &&
metadataAmbiguityCollapsesToDocumentLane(followupSeed.metadataAmbiguityEntitySets) &&
followupSeed.counterparty &&
!rawLifecycleSignal &&
!rawValueFlowSignal &&
!rawMetadataSignal &&
!metadataDocumentHintSignal &&
!metadataMovementHintSignal &&
hasMetadataDownstreamContinuationSignal(rawText)
);
const metadataAmbiguityCollapsedMovementLaneContinuationApplicable = Boolean(
followupSeed.pilotScope === "metadata_inspection_v1" &&
followupSeed.metadataAmbiguityDetected &&
metadataAmbiguityCollapsesToMovementLane(followupSeed.metadataAmbiguityEntitySets) &&
followupSeed.counterparty &&
!rawLifecycleSignal &&
!rawValueFlowSignal &&
!rawMetadataSignal &&
!metadataDocumentHintSignal &&
!metadataMovementHintSignal &&
hasMetadataDownstreamContinuationSignal(rawText)
);
const metadataGroundedDocumentLaneApplicable =
metadataGroundedDocumentFollowupApplicable ||
metadataAmbiguityResolvedDocumentFollowupApplicable ||
(metadataGroundedLaneContinuationApplicable && followupSeed.metadataRouteFamily === "document_evidence");
(metadataGroundedLaneContinuationApplicable && followupSeed.metadataRouteFamily === "document_evidence") ||
metadataAmbiguityCollapsedDocumentLaneContinuationApplicable;
const metadataGroundedMovementLaneApplicable =
metadataGroundedMovementFollowupApplicable ||
metadataAmbiguityResolvedMovementFollowupApplicable ||
(metadataGroundedLaneContinuationApplicable && followupSeed.metadataRouteFamily === "movement_evidence");
(metadataGroundedLaneContinuationApplicable && followupSeed.metadataRouteFamily === "movement_evidence") ||
metadataAmbiguityCollapsedMovementLaneContinuationApplicable;
const effectiveMetadataFollowupSeedApplicable =
metadataFollowupSeedApplicable &&
!metadataGroundedDocumentLaneApplicable &&
@@ -784,6 +834,12 @@ export function buildAssistantMcpDiscoveryTurnInput(
if (metadataGroundedLaneContinuationApplicable) {
pushReason(reasonCodes, "mcp_discovery_metadata_grounded_lane_continuation");
}
if (metadataAmbiguityCollapsedDocumentLaneContinuationApplicable) {
pushReason(reasonCodes, "mcp_discovery_metadata_ambiguity_collapsed_to_document_lane");
}
if (metadataAmbiguityCollapsedMovementLaneContinuationApplicable) {
pushReason(reasonCodes, "mcp_discovery_metadata_ambiguity_collapsed_to_movement_lane");
}
if (unsupported) {
pushReason(reasonCodes, "mcp_discovery_unsupported_but_understood_turn");
}
@@ -11,6 +11,7 @@ import {
readAddressDebugFilters,
readAddressDebugItem,
readAssistantMcpDiscoveryMetadataAmbiguityDetected,
readAssistantMcpDiscoveryMetadataAmbiguityEntitySets,
readAssistantMcpDiscoveryMetadataRouteFamily,
readAssistantMcpDiscoveryMetadataSelectedEntitySet,
readAddressDebugTemporalScope,
@@ -621,6 +622,10 @@ export function createAssistantTransitionPolicy(deps) {
const sourceDiscoveryMetadataAmbiguityDetected = readAssistantMcpDiscoveryMetadataAmbiguityDetected(
carryoverSourceDebug
);
const sourceDiscoveryMetadataAmbiguityEntitySets = readAssistantMcpDiscoveryMetadataAmbiguityEntitySets(
carryoverSourceDebug,
deps.toNonEmptyString
);
const llmExplicitIntent = deps.toNonEmptyString(llmPreDecomposeMeta?.predecomposeContract?.intent);
const llmSelectedObjectScopeDetected =
llmPreDecomposeMeta?.predecomposeContract?.semantics?.selected_object_scope_detected === true;
@@ -956,6 +961,8 @@ export function createAssistantTransitionPolicy(deps) {
previous_discovery_metadata_route_family: sourceDiscoveryMetadataRouteFamily ?? undefined,
previous_discovery_metadata_selected_entity_set: sourceDiscoveryMetadataSelectedEntitySet ?? undefined,
previous_discovery_metadata_ambiguity_detected: sourceDiscoveryMetadataAmbiguityDetected || undefined,
previous_discovery_metadata_ambiguity_entity_sets:
sourceDiscoveryMetadataAmbiguityEntitySets.length > 0 ? sourceDiscoveryMetadataAmbiguityEntitySets : undefined,
resolved_counterparty_from_display: resolvedCounterpartyFromDisplay || undefined,
root_context_only: rootScopedPivot || undefined,
root_intent: shouldAttachInventoryRootFrame ? inventoryRootFrame?.intent ?? undefined : undefined,