ARCH: добить all-time и period-first clarification loops

This commit is contained in:
2026-04-23 13:00:54 +03:00
parent 053a3bf157
commit 8a1ae696dc
16 changed files with 397 additions and 26 deletions
@@ -65,7 +65,13 @@ const PRIMITIVE_CONTRACTS = [
supported_fact_families: ["value_flow", "movement_evidence"],
supported_action_families: ["turnover", "payout", "net_value_flow", "list_movements"],
planning_tags: ["movement", "comparison", "ranking", "aggregation", "monthly_aggregation"],
required_axes_any_of: [["period", "account"], ["period", "counterparty"], ["period", "organization"]],
required_axes_any_of: [
["period", "account"],
["period", "counterparty"],
["period", "organization"],
["all_time_scope", "counterparty"],
["all_time_scope", "organization"]
],
optional_axes: ["contract", "document", "amount", "item", "warehouse"],
output_fact_kinds: ["movement_rows", "turnover", "balance_delta"],
evidence_floor: "rows_matched",
@@ -93,7 +99,13 @@ const PRIMITIVE_CONTRACTS = [
supported_fact_families: ["value_flow"],
supported_action_families: ["turnover", "payout", "net_value_flow"],
planning_tags: ["aggregation", "ranking", "monthly_aggregation"],
required_axes_any_of: [["aggregate_axis", "period"], ["aggregate_axis", "counterparty"], ["aggregate_axis", "account"]],
required_axes_any_of: [
["aggregate_axis", "period"],
["aggregate_axis", "counterparty"],
["aggregate_axis", "account"],
["aggregate_axis", "counterparty", "all_time_scope"],
["aggregate_axis", "organization", "all_time_scope"]
],
optional_axes: ["organization", "contract", "document", "amount"],
output_fact_kinds: ["aggregate_totals", "ranked_axis_values"],
evidence_floor: "rows_matched",
@@ -46,7 +46,6 @@ function isInternalMechanicsLine(value) {
text.includes("runtime_") ||
text.includes("planner_") ||
text.includes("catalog_") ||
text.includes("mcp discovery") ||
text.includes("needs more scope before execution") ||
text.includes("mcp_execution_performed"));
}
@@ -100,10 +100,10 @@ function hasOpenScopeOneSidedValueTotalHint(rawUtterance, action) {
return false;
}
if (action === "turnover") {
return /(?:\bсколько\s+(?:мы\s+)?(?:получили|получено|входящих(?:\s+денег)?|поступлений|денег\s+пришло)\b|(?:сумма|объем)\s+(?:входящих|поступлений)|поступлений\s+за\b)/iu.test(rawUtterance);
return /(?:\bсколько\s+(?:(?:вообще|всего|реально)\s+){0,2}(?:мы\s+)?(?:получили|получено|входящих(?:\s+денег)?(?:\s+было)?|поступлений|денег\s+пришло)\b|(?:сумма|объем)\s+(?:входящих|поступлений)|поступлений\s+за\b)/iu.test(rawUtterance);
}
if (action === "payout") {
return /(?:\bсколько\s+(?:мы\s+)?(?:заплатили|выплатили|потратили|исходящих(?:\s+денег)?|платежей|списаний)\b|(?:сумма|объем)\s+(?:исходящих|платежей|списаний)|(?:платежей|списаний)\s+за\b)/iu.test(rawUtterance);
return /(?:\bсколько\s+(?:(?:вообще|всего|реально)\s+){0,2}(?:мы\s+)?(?:заплатили|выплатили|потратили|исходящих(?:\s+денег)?(?:\s+было)?|платежей(?:\s+было)?|списаний(?:\s+было)?)\b|(?:сумма|объем)\s+(?:исходящих|платежей|списаний)|(?:платежей|списаний)\s+за\b)/iu.test(rawUtterance);
}
return false;
}
@@ -112,10 +112,10 @@ function hasOpenScopeOneSidedValueTotalHintUtf8Safe(rawUtterance, action) {
return false;
}
if (action === "turnover") {
return /(?:\u0441\u043a\u043e\u043b\u044c\u043a\u043e\s+(?:\u043c\u044b\s+)?(?:\u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438|\u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043e|\u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0445(?:\s+\u0434\u0435\u043d\u0435\u0433)?|\u043f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0439|\u0434\u0435\u043d\u0435\u0433\s+\u043f\u0440\u0438\u0448\u043b\u043e)|(?:\u0441\u0443\u043c\u043c\u0430|\u043e\u0431\u044a\u0435\u043c)\s+(?:\u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0445|\u043f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0439)|\u043f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0439\s+\u0437\u0430)/u.test(rawUtterance);
return /(?:\u0441\u043a\u043e\u043b\u044c\u043a\u043e\s+(?:(?:\u0432\u043e\u043e\u0431\u0449\u0435|\u0432\u0441\u0435\u0433\u043e|\u0440\u0435\u0430\u043b\u044c\u043d\u043e)\s+){0,2}(?:\u043c\u044b\s+)?(?:\u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438|\u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043e|\u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0445(?:\s+\u0434\u0435\u043d\u0435\u0433)?(?:\s+\u0431\u044b\u043b\u043e)?|\u043f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0439|\u0434\u0435\u043d\u0435\u0433\s+\u043f\u0440\u0438\u0448\u043b\u043e)|(?:\u0441\u0443\u043c\u043c\u0430|\u043e\u0431\u044a\u0435\u043c)\s+(?:\u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0445|\u043f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0439)|\u043f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0439\s+\u0437\u0430)/u.test(rawUtterance);
}
if (action === "payout") {
return /(?:\u0441\u043a\u043e\u043b\u044c\u043a\u043e\s+(?:\u043c\u044b\s+)?(?:\u0437\u0430\u043f\u043b\u0430\u0442\u0438\u043b\u0438|\u0432\u044b\u043f\u043b\u0430\u0442\u0438\u043b\u0438|\u043f\u043e\u0442\u0440\u0430\u0442\u0438\u043b\u0438|\u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0438\u0445(?:\s+\u0434\u0435\u043d\u0435\u0433)?|\u043f\u043b\u0430\u0442\u0435\u0436\u0435\u0439|\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u0439)|(?:\u0441\u0443\u043c\u043c\u0430|\u043e\u0431\u044a\u0435\u043c)\s+(?:\u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0438\u0445|\u043f\u043b\u0430\u0442\u0435\u0436\u0435\u0439|\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u0439)|(?:\u043f\u043b\u0430\u0442\u0435\u0436\u0435\u0439|\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u0439)\s+\u0437\u0430)/u.test(rawUtterance);
return /(?:\u0441\u043a\u043e\u043b\u044c\u043a\u043e\s+(?:(?:\u0432\u043e\u043e\u0431\u0449\u0435|\u0432\u0441\u0435\u0433\u043e|\u0440\u0435\u0430\u043b\u044c\u043d\u043e)\s+){0,2}(?:\u043c\u044b\s+)?(?:\u0437\u0430\u043f\u043b\u0430\u0442\u0438\u043b\u0438|\u0432\u044b\u043f\u043b\u0430\u0442\u0438\u043b\u0438|\u043f\u043e\u0442\u0440\u0430\u0442\u0438\u043b\u0438|\u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0438\u0445(?:\s+\u0434\u0435\u043d\u0435\u0433)?(?:\s+\u0431\u044b\u043b\u043e)?|\u043f\u043b\u0430\u0442\u0435\u0436\u0435\u0439(?:\s+\u0431\u044b\u043b\u043e)?|\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u0439(?:\s+\u0431\u044b\u043b\u043e)?)|(?:\u0441\u0443\u043c\u043c\u0430|\u043e\u0431\u044a\u0435\u043c)\s+(?:\u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0438\u0445|\u043f\u043b\u0430\u0442\u0435\u0436\u0435\u0439|\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u0439)|(?:\u043f\u043b\u0430\u0442\u0435\u0436\u0435\u0439|\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u0439)\s+\u0437\u0430)/u.test(rawUtterance);
}
return false;
}
@@ -58,6 +58,11 @@ function addScopeAxes(axes, meaning) {
pushUnique(axes, "period");
}
}
function addTimeScopeAxes(axes, dataNeedGraph) {
if (dataNeedGraph?.time_scope_need === "all_time_scope") {
pushUnique(axes, "all_time_scope");
}
}
function includesAny(text, tokens) {
return tokens.some((token) => text.includes(token));
}
@@ -276,6 +281,7 @@ function recipeFor(input) {
const axes = [];
const requestedAggregationAxis = aggregationAxis(meaning);
addScopeAxes(axes, meaning);
addTimeScopeAxes(axes, dataNeedGraph);
if (graphClarificationGaps.includes("lane_family_choice")) {
pushUnique(axes, "lane_family_choice");
return {
@@ -56,7 +56,6 @@ function hasInternalMechanics(value) {
text.includes("planner_") ||
text.includes("catalog_") ||
text.includes("select ") ||
text.includes("mcp discovery") ||
text.includes("needs more scope before execution") ||
text.includes("mcp_execution_performed"));
}
@@ -768,14 +768,27 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
? null
: predecomposeEntities.counterparty;
const predecomposeDateScope = collectDateScope(predecomposeContract);
const periodClarificationFollowupApplicable = Boolean(followupSeed.domain &&
followupSeed.loopStatus === "awaiting_clarification" &&
followupSeed.loopPendingAxes.includes("period") &&
!rawLifecycleSignal &&
!rawMetadataSignal &&
(rawAllTimeScopeSignal ||
explicitDateScopeLiteralDetected ||
rawDateScope ||
relativeCurrentDateHintDetected ||
(predecomposeDateScope && !isImplicitCurrentDateScope(predecomposeDateScope))));
const followupDiscoverySeedApplicable = Boolean(followupSeed.domain &&
!rawLifecycleSignal &&
!rawValueFlowSignal &&
(monthlyAggregationSignal ||
explicitDateScopeLiteralDetected ||
predecomposeDateScope ||
explicitOrganizationScopeSignal ||
organizationClarificationFollowupApplicable));
!rawMetadataSignal &&
(periodClarificationFollowupApplicable ||
(!rawValueFlowSignal &&
(monthlyAggregationSignal ||
rawAllTimeScopeSignal ||
explicitDateScopeLiteralDetected ||
predecomposeDateScope ||
explicitOrganizationScopeSignal ||
organizationClarificationFollowupApplicable))));
const metadataFollowupSeedApplicable = Boolean(followupSeed.domain === "metadata" &&
!rawLifecycleSignal &&
!rawValueFlowSignal &&
@@ -1197,6 +1210,7 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
groundedValueFlowFollowupApplicable,
forceDiscoveryOverExplicitIntent: Boolean(entityResolutionClarificationCandidate) ||
organizationClarificationFollowupApplicable ||
periodClarificationFollowupApplicable ||
metadataAmbiguityLaneClarificationApplicable ||
metadataGroundedMovementLaneApplicable ||
metadataGroundedDocumentLaneApplicable ||
@@ -1249,6 +1263,9 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
if (organizationClarificationFollowupApplicable) {
pushReason(reasonCodes, "mcp_discovery_organization_clarification_followup_from_followup_context");
}
if (periodClarificationFollowupApplicable) {
pushReason(reasonCodes, "mcp_discovery_period_clarification_followup_from_followup_context");
}
if (payoutSignal) {
pushReason(reasonCodes, "mcp_discovery_payout_signal_detected");
}