ARCH: добавить помесячный MCP discovery для нетто-потока
This commit is contained in:
+70
-1
@@ -65,6 +65,17 @@ function isValueFlowPilot(pilot) {
|
||||
pilot.pilot_scope === "counterparty_bidirectional_value_flow_query_movements_v1");
|
||||
}
|
||||
function headlineFor(mode, pilot) {
|
||||
const askedMonthlyBreakdown = pilot.derived_bidirectional_value_flow?.aggregation_axis === "month" ||
|
||||
pilot.derived_value_flow?.aggregation_axis === "month";
|
||||
if (askedMonthlyBreakdown && pilot.derived_bidirectional_value_flow && mode === "confirmed_with_bounded_inference") {
|
||||
return "По данным 1С найдены строки входящих и исходящих денежных движений; нетто и помесячная раскладка могут называться только как расчет по найденным строкам и проверенному периоду.";
|
||||
}
|
||||
if (askedMonthlyBreakdown && pilot.derived_value_flow && mode === "confirmed_with_bounded_inference") {
|
||||
if (pilot.derived_value_flow.value_flow_direction === "outgoing_supplier_payout") {
|
||||
return "По данным 1С найдены строки исходящих платежей/списаний; сумму и помесячную раскладку можно называть только в рамках проверенного периода и найденных строк.";
|
||||
}
|
||||
return "По данным 1С найдены строки денежных движений; сумму и помесячную раскладку можно называть только в рамках проверенного периода и найденных строк.";
|
||||
}
|
||||
if (pilot.derived_bidirectional_value_flow && mode === "confirmed_with_bounded_inference") {
|
||||
return "По данным 1С найдены строки входящих и исходящих денежных движений; нетто можно называть только как расчет по найденным строкам и проверенному периоду.";
|
||||
}
|
||||
@@ -118,6 +129,38 @@ function buildMustNotClaim(pilot) {
|
||||
}
|
||||
return claims;
|
||||
}
|
||||
const RU_MONTH_LABELS_SHORT = [
|
||||
"янв",
|
||||
"фев",
|
||||
"мар",
|
||||
"апр",
|
||||
"май",
|
||||
"июн",
|
||||
"июл",
|
||||
"авг",
|
||||
"сен",
|
||||
"окт",
|
||||
"ноя",
|
||||
"дек"
|
||||
];
|
||||
function monthLabelRu(monthBucket) {
|
||||
const match = monthBucket.match(/^(\d{4})-(\d{2})$/);
|
||||
if (!match) {
|
||||
return monthBucket;
|
||||
}
|
||||
const monthIndex = Number(match[2]) - 1;
|
||||
const label = RU_MONTH_LABELS_SHORT[monthIndex] ?? match[2];
|
||||
return `${label} ${match[1]}`;
|
||||
}
|
||||
function netLabelRu(netDirection) {
|
||||
if (netDirection === "net_incoming") {
|
||||
return "нетто в нашу сторону";
|
||||
}
|
||||
if (netDirection === "net_outgoing") {
|
||||
return "нетто исходящее";
|
||||
}
|
||||
return "нетто нулевое";
|
||||
}
|
||||
function derivedActivityInferenceLine(pilot) {
|
||||
const period = pilot.derived_activity_period;
|
||||
if (!period) {
|
||||
@@ -151,6 +194,19 @@ function derivedValueFlowConfirmedLine(pilot) {
|
||||
: "";
|
||||
return `По найденным строкам ${movementLabel} в 1С${counterparty}${period} ${totalLabel} ${flow.total_amount_human_ru} Учтено строк с суммой: ${flow.rows_with_amount} из ${flow.rows_matched}.${dates}${limitCaveat} ${caveat}`;
|
||||
}
|
||||
function derivedValueFlowMonthlyLines(pilot) {
|
||||
const flow = pilot.derived_value_flow;
|
||||
if (!flow || flow.aggregation_axis !== "month" || flow.monthly_breakdown.length === 0) {
|
||||
return [];
|
||||
}
|
||||
return flow.monthly_breakdown.map((bucket) => {
|
||||
const monthLabel = monthLabelRu(bucket.month_bucket);
|
||||
if (flow.value_flow_direction === "outgoing_supplier_payout") {
|
||||
return `Помесячно: ${monthLabel} — заплатили ${bucket.total_amount_human_ru} по ${bucket.rows_with_amount} строкам с суммой`;
|
||||
}
|
||||
return `Помесячно: ${monthLabel} — получили ${bucket.total_amount_human_ru} по ${bucket.rows_with_amount} строкам с суммой`;
|
||||
});
|
||||
}
|
||||
function sideDateRange(first, latest) {
|
||||
if (first && latest) {
|
||||
return ` первая дата ${first}, последняя ${latest}`;
|
||||
@@ -185,6 +241,13 @@ function derivedBidirectionalValueFlowConfirmedLine(pilot) {
|
||||
.replace(/\s+/g, " ")
|
||||
.trim();
|
||||
}
|
||||
function derivedBidirectionalValueFlowMonthlyLines(pilot) {
|
||||
const flow = pilot.derived_bidirectional_value_flow;
|
||||
if (!flow || flow.aggregation_axis !== "month" || flow.monthly_breakdown.length === 0) {
|
||||
return [];
|
||||
}
|
||||
return flow.monthly_breakdown.map((bucket) => `Помесячно: ${monthLabelRu(bucket.month_bucket)} — получили ${bucket.incoming_total_amount_human_ru}, заплатили ${bucket.outgoing_total_amount_human_ru}, ${netLabelRu(bucket.net_direction)} ${bucket.net_amount_human_ru}`);
|
||||
}
|
||||
function buildAssistantMcpDiscoveryAnswerDraft(pilot) {
|
||||
const mode = modeFor(pilot);
|
||||
const reasonCodes = [...pilot.reason_codes, ...pilot.evidence.reason_codes];
|
||||
@@ -200,8 +263,14 @@ function buildAssistantMcpDiscoveryAnswerDraft(pilot) {
|
||||
? [derivedInferenceLine]
|
||||
: pilot.evidence.inferred_facts;
|
||||
const derivedValueLine = derivedBidirectionalValueFlowConfirmedLine(pilot) ?? derivedValueFlowConfirmedLine(pilot);
|
||||
const monthlyConfirmedLines = derivedBidirectionalValueFlowMonthlyLines(pilot).length > 0
|
||||
? derivedBidirectionalValueFlowMonthlyLines(pilot)
|
||||
: derivedValueFlowMonthlyLines(pilot);
|
||||
if (monthlyConfirmedLines.length > 0) {
|
||||
pushReason(reasonCodes, "answer_contains_monthly_breakdown");
|
||||
}
|
||||
const confirmedLines = derivedValueLine
|
||||
? [...pilot.evidence.confirmed_facts, derivedValueLine]
|
||||
? [...pilot.evidence.confirmed_facts, derivedValueLine, ...monthlyConfirmedLines]
|
||||
: pilot.evidence.confirmed_facts;
|
||||
return {
|
||||
schema_version: exports.ASSISTANT_MCP_DISCOVERY_ANSWER_DRAFT_SCHEMA_VERSION,
|
||||
|
||||
+114
-7
@@ -37,6 +37,10 @@ function pushUnique(target, value) {
|
||||
target.push(text);
|
||||
}
|
||||
}
|
||||
function aggregationAxisForPlanner(planner) {
|
||||
const axis = toNonEmptyString(planner.discovery_plan.turn_meaning_ref?.asked_aggregation_axis)?.toLowerCase();
|
||||
return axis === "month" ? "month" : null;
|
||||
}
|
||||
function firstEntityCandidate(planner) {
|
||||
const candidates = planner.discovery_plan.turn_meaning_ref?.explicit_entity_candidates ?? [];
|
||||
for (const candidate of candidates) {
|
||||
@@ -231,6 +235,19 @@ function rowAmountValue(row) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function monthBucketFromIsoDate(isoDate) {
|
||||
const match = isoDate?.match(/^(\d{4})-(\d{2})-\d{2}$/);
|
||||
return match ? `${match[1]}-${match[2]}` : null;
|
||||
}
|
||||
function netDirectionFromAmount(amount) {
|
||||
if (amount > 0) {
|
||||
return "net_incoming";
|
||||
}
|
||||
if (amount < 0) {
|
||||
return "net_outgoing";
|
||||
}
|
||||
return "balanced";
|
||||
}
|
||||
function monthDiff(firstIsoDate, latestIsoDate) {
|
||||
const first = new Date(`${firstIsoDate}T00:00:00.000Z`);
|
||||
const latest = new Date(`${latestIsoDate}T00:00:00.000Z`);
|
||||
@@ -290,7 +307,70 @@ function formatAmountHumanRu(amount) {
|
||||
.replace(/\u00a0/g, " ");
|
||||
return `${formatted} руб.`;
|
||||
}
|
||||
function deriveValueFlow(result, counterparty, periodScope, direction, probeLimit) {
|
||||
function deriveValueFlowMonthBreakdown(result, aggregationAxis) {
|
||||
if (!result || result.error || aggregationAxis !== "month") {
|
||||
return [];
|
||||
}
|
||||
const buckets = new Map();
|
||||
for (const row of result.rows) {
|
||||
const isoDate = rowDateValue(row);
|
||||
const monthBucket = monthBucketFromIsoDate(isoDate);
|
||||
const amount = rowAmountValue(row);
|
||||
if (!monthBucket || amount === null) {
|
||||
continue;
|
||||
}
|
||||
const current = buckets.get(monthBucket) ?? { rows_with_amount: 0, total_amount: 0 };
|
||||
current.rows_with_amount += 1;
|
||||
current.total_amount += amount;
|
||||
buckets.set(monthBucket, current);
|
||||
}
|
||||
return Array.from(buckets.entries())
|
||||
.sort(([left], [right]) => left.localeCompare(right))
|
||||
.map(([monthBucket, bucket]) => ({
|
||||
month_bucket: monthBucket,
|
||||
rows_with_amount: bucket.rows_with_amount,
|
||||
total_amount: bucket.total_amount,
|
||||
total_amount_human_ru: formatAmountHumanRu(bucket.total_amount)
|
||||
}));
|
||||
}
|
||||
function deriveBidirectionalValueFlowMonthBreakdown(input) {
|
||||
if (input.aggregationAxis !== "month") {
|
||||
return [];
|
||||
}
|
||||
const incomingBuckets = deriveValueFlowMonthBreakdown(input.incomingResult, "month");
|
||||
const outgoingBuckets = deriveValueFlowMonthBreakdown(input.outgoingResult, "month");
|
||||
const allMonthBuckets = new Set();
|
||||
for (const bucket of incomingBuckets) {
|
||||
allMonthBuckets.add(bucket.month_bucket);
|
||||
}
|
||||
for (const bucket of outgoingBuckets) {
|
||||
allMonthBuckets.add(bucket.month_bucket);
|
||||
}
|
||||
const incomingByMonth = new Map(incomingBuckets.map((bucket) => [bucket.month_bucket, bucket]));
|
||||
const outgoingByMonth = new Map(outgoingBuckets.map((bucket) => [bucket.month_bucket, bucket]));
|
||||
return Array.from(allMonthBuckets)
|
||||
.sort((left, right) => left.localeCompare(right))
|
||||
.map((monthBucket) => {
|
||||
const incoming = incomingByMonth.get(monthBucket);
|
||||
const outgoing = outgoingByMonth.get(monthBucket);
|
||||
const incomingAmount = incoming?.total_amount ?? 0;
|
||||
const outgoingAmount = outgoing?.total_amount ?? 0;
|
||||
const netAmount = incomingAmount - outgoingAmount;
|
||||
return {
|
||||
month_bucket: monthBucket,
|
||||
incoming_total_amount: incomingAmount,
|
||||
incoming_total_amount_human_ru: formatAmountHumanRu(incomingAmount),
|
||||
incoming_rows_with_amount: incoming?.rows_with_amount ?? 0,
|
||||
outgoing_total_amount: outgoingAmount,
|
||||
outgoing_total_amount_human_ru: formatAmountHumanRu(outgoingAmount),
|
||||
outgoing_rows_with_amount: outgoing?.rows_with_amount ?? 0,
|
||||
net_amount: netAmount,
|
||||
net_amount_human_ru: formatAmountHumanRu(Math.abs(netAmount)),
|
||||
net_direction: netDirectionFromAmount(netAmount)
|
||||
};
|
||||
});
|
||||
}
|
||||
function deriveValueFlow(result, counterparty, periodScope, direction, probeLimit, aggregationAxis) {
|
||||
if (!result || result.error || result.matched_rows <= 0) {
|
||||
return null;
|
||||
}
|
||||
@@ -314,6 +394,7 @@ function deriveValueFlow(result, counterparty, periodScope, direction, probeLimi
|
||||
value_flow_direction: direction,
|
||||
counterparty,
|
||||
period_scope: periodScope,
|
||||
aggregation_axis: aggregationAxis,
|
||||
rows_matched: result.matched_rows,
|
||||
rows_with_amount: rowsWithAmount,
|
||||
total_amount: totalAmount,
|
||||
@@ -321,6 +402,7 @@ function deriveValueFlow(result, counterparty, periodScope, direction, probeLimi
|
||||
first_movement_date: dates[0] ?? null,
|
||||
latest_movement_date: dates[dates.length - 1] ?? null,
|
||||
coverage_limited_by_probe_limit: result.matched_rows >= probeLimit,
|
||||
monthly_breakdown: deriveValueFlowMonthBreakdown(result, aggregationAxis),
|
||||
inference_basis: "sum_of_confirmed_1c_value_flow_rows"
|
||||
};
|
||||
}
|
||||
@@ -369,12 +451,18 @@ function deriveBidirectionalValueFlow(input) {
|
||||
return {
|
||||
counterparty: input.counterparty,
|
||||
period_scope: input.periodScope,
|
||||
aggregation_axis: input.aggregationAxis,
|
||||
incoming_customer_revenue: incoming,
|
||||
outgoing_supplier_payout: outgoing,
|
||||
net_amount: netAmount,
|
||||
net_amount_human_ru: formatAmountHumanRu(Math.abs(netAmount)),
|
||||
net_direction: netAmount > 0 ? "net_incoming" : netAmount < 0 ? "net_outgoing" : "balanced",
|
||||
net_direction: netDirectionFromAmount(netAmount),
|
||||
coverage_limited_by_probe_limit: incoming.coverage_limited_by_probe_limit || outgoing.coverage_limited_by_probe_limit,
|
||||
monthly_breakdown: deriveBidirectionalValueFlowMonthBreakdown({
|
||||
incomingResult: input.incomingResult,
|
||||
outgoingResult: input.outgoingResult,
|
||||
aggregationAxis: input.aggregationAxis
|
||||
}),
|
||||
inference_basis: "incoming_minus_outgoing_confirmed_1c_value_flow_rows"
|
||||
};
|
||||
}
|
||||
@@ -444,16 +532,27 @@ function buildValueFlowInferredFacts(derived) {
|
||||
if (!derived) {
|
||||
return [];
|
||||
}
|
||||
const facts = [];
|
||||
if (derived.value_flow_direction === "outgoing_supplier_payout") {
|
||||
return ["Counterparty supplier-payout total was calculated from confirmed 1C outgoing payment rows"];
|
||||
facts.push("Counterparty supplier-payout total was calculated from confirmed 1C outgoing payment rows");
|
||||
}
|
||||
return ["Counterparty value-flow total was calculated from confirmed 1C movement rows"];
|
||||
else {
|
||||
facts.push("Counterparty value-flow total was calculated from confirmed 1C movement rows");
|
||||
}
|
||||
if (derived.aggregation_axis === "month" && derived.monthly_breakdown.length > 0) {
|
||||
facts.push("Counterparty monthly value-flow breakdown was grouped by month over confirmed 1C movement rows");
|
||||
}
|
||||
return facts;
|
||||
}
|
||||
function buildBidirectionalValueFlowInferredFacts(derived) {
|
||||
if (!derived) {
|
||||
return [];
|
||||
}
|
||||
return ["Counterparty net value-flow was calculated as incoming confirmed 1C rows minus outgoing confirmed 1C rows"];
|
||||
const facts = ["Counterparty net value-flow was calculated as incoming confirmed 1C rows minus outgoing confirmed 1C rows"];
|
||||
if (derived.aggregation_axis === "month" && derived.monthly_breakdown.length > 0) {
|
||||
facts.push("Counterparty monthly net value-flow breakdown was grouped by month over confirmed incoming and outgoing 1C rows");
|
||||
}
|
||||
return facts;
|
||||
}
|
||||
function buildLifecycleUnknownFacts() {
|
||||
return ["Legal registration date is not proven by this MCP discovery pilot"];
|
||||
@@ -574,6 +673,7 @@ async function executeAssistantMcpDiscoveryPilot(planner, deps = DEFAULT_DEPS) {
|
||||
}
|
||||
const counterparty = firstEntityCandidate(planner);
|
||||
const dateScope = toNonEmptyString(planner.discovery_plan.turn_meaning_ref?.explicit_date_scope);
|
||||
const aggregationAxis = aggregationAxisForPlanner(planner);
|
||||
if (valueFlowPilotEligible) {
|
||||
let queryResult = null;
|
||||
const filters = buildValueFlowFilters(planner);
|
||||
@@ -645,10 +745,14 @@ async function executeAssistantMcpDiscoveryPilot(planner, deps = DEFAULT_DEPS) {
|
||||
outgoingResult,
|
||||
counterparty,
|
||||
periodScope: dateScope,
|
||||
probeLimit: planner.discovery_plan.execution_budget.max_rows_per_probe
|
||||
probeLimit: planner.discovery_plan.execution_budget.max_rows_per_probe,
|
||||
aggregationAxis
|
||||
});
|
||||
if (derivedBidirectionalValueFlow) {
|
||||
pushReason(reasonCodes, "pilot_derived_bidirectional_value_flow_from_confirmed_rows");
|
||||
if (aggregationAxis === "month" && derivedBidirectionalValueFlow.monthly_breakdown.length > 0) {
|
||||
pushReason(reasonCodes, "pilot_derived_bidirectional_monthly_breakdown_from_confirmed_rows");
|
||||
}
|
||||
}
|
||||
const evidence = (0, assistantMcpDiscoveryPolicy_1.resolveAssistantMcpDiscoveryEvidence)({
|
||||
plan: planner.discovery_plan,
|
||||
@@ -729,9 +833,12 @@ async function executeAssistantMcpDiscoveryPilot(planner, deps = DEFAULT_DEPS) {
|
||||
}
|
||||
}
|
||||
const sourceRowsSummary = queryResult ? summarizeValueFlowRows(queryResult) : null;
|
||||
const derivedValueFlow = deriveValueFlow(queryResult, counterparty, dateScope, valueFlowProfile.direction, planner.discovery_plan.execution_budget.max_rows_per_probe);
|
||||
const derivedValueFlow = deriveValueFlow(queryResult, counterparty, dateScope, valueFlowProfile.direction, planner.discovery_plan.execution_budget.max_rows_per_probe, aggregationAxis);
|
||||
if (derivedValueFlow) {
|
||||
pushReason(reasonCodes, "pilot_derived_value_flow_from_confirmed_rows");
|
||||
if (aggregationAxis === "month" && derivedValueFlow.monthly_breakdown.length > 0) {
|
||||
pushReason(reasonCodes, "pilot_derived_value_flow_monthly_breakdown_from_confirmed_rows");
|
||||
}
|
||||
}
|
||||
const evidence = (0, assistantMcpDiscoveryPolicy_1.resolveAssistantMcpDiscoveryEvidence)({
|
||||
plan: planner.discovery_plan,
|
||||
|
||||
@@ -38,6 +38,9 @@ function pushUnique(target, value) {
|
||||
function hasEntity(meaning) {
|
||||
return (meaning?.explicit_entity_candidates?.length ?? 0) > 0;
|
||||
}
|
||||
function aggregationAxis(meaning) {
|
||||
return toNonEmptyString(meaning?.asked_aggregation_axis)?.toLowerCase() ?? null;
|
||||
}
|
||||
function addScopeAxes(axes, meaning) {
|
||||
if (hasEntity(meaning)) {
|
||||
pushUnique(axes, "counterparty");
|
||||
@@ -59,16 +62,22 @@ function recipeFor(input) {
|
||||
const unsupported = lower(meaning?.unsupported_but_understood_family);
|
||||
const combined = `${domain} ${action} ${unsupported}`.trim();
|
||||
const axes = [];
|
||||
const requestedAggregationAxis = aggregationAxis(meaning);
|
||||
addScopeAxes(axes, meaning);
|
||||
if (includesAny(combined, ["turnover", "revenue", "payment", "payout", "value", "net", "netting", "balance", "cashflow"])) {
|
||||
pushUnique(axes, "aggregate_axis");
|
||||
pushUnique(axes, "amount");
|
||||
pushUnique(axes, "coverage_target");
|
||||
if (requestedAggregationAxis === "month") {
|
||||
pushUnique(axes, "calendar_month");
|
||||
}
|
||||
return {
|
||||
semanticDataNeed: "counterparty value-flow evidence",
|
||||
primitives: ["resolve_entity_reference", "query_movements", "aggregate_by_axis", "probe_coverage"],
|
||||
axes,
|
||||
reason: "planner_selected_value_flow_recipe"
|
||||
reason: requestedAggregationAxis === "month"
|
||||
? "planner_selected_monthly_value_flow_recipe"
|
||||
: "planner_selected_value_flow_recipe"
|
||||
};
|
||||
}
|
||||
if (includesAny(combined, ["document", "documents"])) {
|
||||
|
||||
@@ -74,6 +74,7 @@ function normalizeTurnMeaning(value) {
|
||||
const result = {};
|
||||
const domain = toNonEmptyString(value.asked_domain_family);
|
||||
const action = toNonEmptyString(value.asked_action_family);
|
||||
const aggregationAxis = toNonEmptyString(value.asked_aggregation_axis);
|
||||
const organization = toNonEmptyString(value.explicit_organization_scope);
|
||||
const dateScope = toNonEmptyString(value.explicit_date_scope);
|
||||
const unsupported = toNonEmptyString(value.unsupported_but_understood_family);
|
||||
@@ -84,6 +85,9 @@ function normalizeTurnMeaning(value) {
|
||||
if (action) {
|
||||
result.asked_action_family = action;
|
||||
}
|
||||
if (aggregationAxis) {
|
||||
result.asked_aggregation_axis = aggregationAxis;
|
||||
}
|
||||
if (entities.length > 0) {
|
||||
result.explicit_entity_candidates = entities;
|
||||
}
|
||||
|
||||
+6
@@ -100,12 +100,18 @@ function localizeLine(value) {
|
||||
if (/^Counterparty value-flow total was calculated from confirmed 1C movement rows$/i.test(value)) {
|
||||
return "Сумма рассчитана только по подтвержденным строкам денежных движений в 1С.";
|
||||
}
|
||||
if (/^Counterparty monthly value-flow breakdown was grouped by month over confirmed 1C movement rows$/i.test(value)) {
|
||||
return "Помесячная раскладка денежного потока сгруппирована только по подтвержденным строкам движений 1С.";
|
||||
}
|
||||
if (/^Counterparty supplier-payout total was calculated from confirmed 1C outgoing payment rows$/i.test(value)) {
|
||||
return "Сумма исходящих платежей рассчитана только по подтвержденным строкам списаний в 1С.";
|
||||
}
|
||||
if (/^Counterparty net value-flow was calculated as incoming confirmed 1C rows minus outgoing confirmed 1C rows$/i.test(value)) {
|
||||
return "Нетто денежного потока рассчитано только как входящие подтвержденные строки 1С минус исходящие подтвержденные строки 1С.";
|
||||
}
|
||||
if (/^Counterparty monthly net value-flow breakdown was grouped by month over confirmed incoming and outgoing 1C rows$/i.test(value)) {
|
||||
return "Помесячная нетто-раскладка сгруппирована только по подтвержденным входящим и исходящим строкам 1С.";
|
||||
}
|
||||
if (/^Legal registration date is not proven by this MCP discovery pilot$/i.test(value)) {
|
||||
return "Юридическая дата регистрации этим поиском не подтверждена.";
|
||||
}
|
||||
|
||||
+12
@@ -104,6 +104,9 @@ function hasPayoutSignal(text) {
|
||||
function hasBidirectionalValueFlowSignal(text) {
|
||||
return /(?:нетто|сальдо|баланс\s+(?:плат|денег|денеж)|взаиморасч[её]т|получил[иа]?.*(?:за)?платил|(?:за)?платил[иа]?.*получил|входящ.*исходящ|исходящ.*входящ|дебет.*кредит|кредит.*дебет|net\s+(?:flow|cash|payment)|cash\s+net|incoming\s+and\s+outgoing|received\s+and\s+paid|paid\s+and\s+received)/iu.test(text);
|
||||
}
|
||||
function hasMonthlyAggregationSignal(text) {
|
||||
return /(?:\u043f\u043e\s+\u043c\u0435\u0441\u044f\u0446\u0430\u043c|\u043f\u043e\u043c\u0435\u0441\u044f\u0447\u043d\u043e|\u0435\u0436\u0435\u043c\u0435\u0441\u044f\u0447\u043d\u043e|month\s+by\s+month|by\s+month|monthly)/iu.test(text);
|
||||
}
|
||||
function semanticNeedFor(input) {
|
||||
const combined = compactLower(`${input.domain ?? ""} ${input.action ?? ""} ${input.unsupported ?? ""}`);
|
||||
if (input.lifecycleSignal || /(?:lifecycle|activity|duration|age)/iu.test(combined)) {
|
||||
@@ -142,8 +145,10 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
|
||||
const bidirectionalValueFlowSignal = !lifecycleSignal && hasBidirectionalValueFlowSignal(rawText);
|
||||
const valueFlowSignal = !lifecycleSignal && (hasValueFlowSignal(rawText) || bidirectionalValueFlowSignal);
|
||||
const payoutSignal = valueFlowSignal && !bidirectionalValueFlowSignal && hasPayoutSignal(rawText);
|
||||
const monthlyAggregationSignal = valueFlowSignal && hasMonthlyAggregationSignal(rawText);
|
||||
const rawDomain = toNonEmptyString(assistantTurnMeaning?.asked_domain_family);
|
||||
const rawAction = toNonEmptyString(assistantTurnMeaning?.asked_action_family);
|
||||
const rawAggregationAxis = toNonEmptyString(assistantTurnMeaning?.asked_aggregation_axis);
|
||||
const unsupported = toNonEmptyString(assistantTurnMeaning?.unsupported_but_understood_family);
|
||||
const explicitIntentCandidate = toNonEmptyString(assistantTurnMeaning?.explicit_intent_candidate);
|
||||
const semanticDataNeed = semanticNeedFor({
|
||||
@@ -170,6 +175,7 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
|
||||
? "payout"
|
||||
: "turnover"
|
||||
: rawAction,
|
||||
asked_aggregation_axis: monthlyAggregationSignal ? "month" : rawAggregationAxis,
|
||||
explicit_entity_candidates: entityCandidates,
|
||||
explicit_organization_scope: explicitOrganizationScope,
|
||||
explicit_date_scope: collectDateScope(predecomposeContract),
|
||||
@@ -192,6 +198,9 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
|
||||
if (toNonEmptyString(turnMeaning.asked_action_family)) {
|
||||
cleanTurnMeaning.asked_action_family = turnMeaning.asked_action_family;
|
||||
}
|
||||
if (toNonEmptyString(turnMeaning.asked_aggregation_axis)) {
|
||||
cleanTurnMeaning.asked_aggregation_axis = turnMeaning.asked_aggregation_axis;
|
||||
}
|
||||
if ((turnMeaning.explicit_entity_candidates?.length ?? 0) > 0) {
|
||||
cleanTurnMeaning.explicit_entity_candidates = turnMeaning.explicit_entity_candidates;
|
||||
}
|
||||
@@ -236,6 +245,9 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
|
||||
if (bidirectionalValueFlowSignal) {
|
||||
pushReason(reasonCodes, "mcp_discovery_bidirectional_value_flow_signal_detected");
|
||||
}
|
||||
if (monthlyAggregationSignal) {
|
||||
pushReason(reasonCodes, "mcp_discovery_monthly_aggregation_signal_detected");
|
||||
}
|
||||
if (unsupported) {
|
||||
pushReason(reasonCodes, "mcp_discovery_unsupported_but_understood_turn");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user