Уточнить subject-оси Autonomy Core 1С

This commit is contained in:
2026-05-23 18:32:36 +03:00
parent 4d1b25cca7
commit 624e0cdf26
8 changed files with 224 additions and 16 deletions
@@ -37,12 +37,29 @@ function uniqueStrings(values) {
function isExplicitDate(value) {
return Boolean(value && /^\d{4}-\d{2}-\d{2}$/.test(value));
}
function providedAxesFromMeaning(meaning, graph) {
const SUBJECT_AXIS_SET = new Set([
"counterparty",
"business_entity",
"item",
"supplier",
"buyer",
"document",
"contract"
]);
function providedAxesFromMeaning(meaning, graph, requiredAxes) {
const result = [];
if ((meaning?.explicit_entity_candidates?.length ?? 0) > 0) {
result.push("counterparty");
result.push("business_entity");
}
if ((graph?.subject_candidates.length ?? 0) > 0) {
result.push("business_entity");
for (const axis of requiredAxes) {
if (SUBJECT_AXIS_SET.has(axis)) {
result.push(axis);
}
}
}
if (toNonEmptyString(meaning?.explicit_organization_scope)) {
result.push("organization");
}
@@ -126,7 +143,7 @@ function buildAssistantEvidencePlanner(input) {
const plan = input.discoveryPlan;
const turnMeaning = plan.turn_meaning_ref;
const requiredAxes = uniqueStrings(plan.required_axes);
const providedAxes = providedAxesFromMeaning(turnMeaning, graph);
const providedAxes = providedAxesFromMeaning(turnMeaning, graph, requiredAxes);
const graphClarificationGaps = uniqueStrings(graph?.clarification_gaps ?? []);
const additionalAxisGaps = uniqueStrings(input.additionalMissingAxes ?? []).filter((axis) => !providedAxes.includes(axis) && (requiredAxes.includes(axis) || USER_ACTIONABLE_AXIS_SET.has(axis)));
const axisGaps = uniqueStrings([...additionalAxisGaps, ...missingAxes(requiredAxes, providedAxes)]);
@@ -178,6 +178,23 @@ function hasOpenScopeOneSidedValueTotalHintUtf8Safe(rawUtterance, action) {
}
return false;
}
function inferredOpenScopeOneSidedValueAction(rawUtterance) {
if (hasOpenScopeOneSidedValueTotalHintUtf8Safe(rawUtterance, "turnover") ||
hasOpenScopeOneSidedValueTotalHint(rawUtterance, "turnover")) {
return "turnover";
}
if (hasOpenScopeOneSidedValueTotalHintUtf8Safe(rawUtterance, "payout") ||
hasOpenScopeOneSidedValueTotalHint(rawUtterance, "payout")) {
return "payout";
}
return null;
}
function hasDetailedBusinessOverviewMoneyBreakdownHint(rawUtterance) {
if (!rawUtterance) {
return false;
}
return /(?:\u0440\u0430\u0441\u043a\u0440\u043e\p{L}*|\u043f\u043e\u0434\u0440\u043e\u0431\p{L}*|\u0440\u0430\u0437\u0431\u0435\p{L}*|\u0440\u0430\u0437\u0432\u0435\u0440\u043d\p{L}*|\u043a\u0442\u043e\s+\u0433\u043b\u0430\u0432\p{L}*|\u0433\u043b\u0430\u0432\p{L}*\s+\u043a\u043b\u0438\u0435\u043d\p{L}*|\u0433\u043b\u0430\u0432\p{L}*\s+\u043f\u043e\u0441\u0442\u0430\u0432\p{L}*|\u0447\u0438\u0441\u0442\p{L}*\s+\u0434\u0435\u043d\u0435\u0436\p{L}*\s+\u043f\u043e\u0442\u043e\p{L}*|\u043f\u043e\u043b\u0443\u0447\p{L}*[\s\S]{0,80}\u0437\u0430\u043f\u043b\u0430\u0442\p{L}*|\u0432\u0445\u043e\u0434\p{L}*[\s\S]{0,80}\u0438\u0441\u0445\u043e\u0434\p{L}*|detail|breakdown|drill\s*down|main\s+customer|main\s+supplier)/iu.test(rawUtterance);
}
function supportsOrganizationScopedOpenTotal(action) {
return action === "turnover" || action === "payout";
}
@@ -393,7 +410,7 @@ function buildAssistantMcpDiscoveryDataNeedGraph(input) {
const semanticDataNeed = lower(input.semanticDataNeed);
const turnMeaning = input.turnMeaning ?? null;
const domain = lower(turnMeaning?.asked_domain_family);
const action = lower(turnMeaning?.asked_action_family);
const rawAction = lower(turnMeaning?.asked_action_family);
const unsupported = lower(turnMeaning?.unsupported_but_understood_family);
const rawUtterance = lower(input.rawUtterance);
const rawQuestionSignal = lower([input.rawUtterance, turnMeaning?.raw_message, turnMeaning?.effective_message].join(" "));
@@ -406,12 +423,19 @@ function buildAssistantMcpDiscoveryDataNeedGraph(input) {
const subjectCandidates = (turnMeaning?.explicit_entity_candidates ?? [])
.map((item) => toNonEmptyString(item))
.filter((item) => Boolean(item));
const businessFactFamily = businessFactFamilyFor({
const initialBusinessFactFamily = businessFactFamilyFor({
semanticDataNeed,
domain,
action,
action: rawAction,
unsupported
});
const oneSidedValueAction = inferredOpenScopeOneSidedValueAction(rawQuestionSignal);
const detailedBusinessOverviewMoneyBreakdownHint = hasDetailedBusinessOverviewMoneyBreakdownHint(rawQuestionSignal);
const oneSidedBusinessOverviewValueFlowOverride = initialBusinessFactFamily === "business_overview" &&
Boolean(oneSidedValueAction) &&
!detailedBusinessOverviewMoneyBreakdownHint;
const action = oneSidedBusinessOverviewValueFlowOverride ? oneSidedValueAction : rawAction;
const businessFactFamily = oneSidedBusinessOverviewValueFlowOverride ? "value_flow" : initialBusinessFactFamily;
const aggregationNeed = aggregationNeedFor(aggregationAxis);
const comparisonNeed = comparisonNeedFor(action);
const allTimeScopeHint = hasAllTimeScopeHint(rawUtterance);
@@ -529,6 +553,9 @@ function buildAssistantMcpDiscoveryDataNeedGraph(input) {
if (directBusinessOverviewMoneyAnswerHint) {
pushReason(reasonCodes, "data_need_graph_business_overview_direct_money_answer");
}
if (oneSidedBusinessOverviewValueFlowOverride) {
pushReason(reasonCodes, "data_need_graph_business_overview_one_sided_money_total_routed_to_value_flow");
}
if (clarificationGaps.includes("organization")) {
pushReason(reasonCodes, "data_need_graph_open_scope_total_needs_organization");
}
@@ -542,7 +569,7 @@ function buildAssistantMcpDiscoveryDataNeedGraph(input) {
metadata_scope_hint: metadataScopeHint,
subject_resolution_optional: subjectResolutionOptional || undefined,
business_fact_family: businessFactFamily,
action_family: toNonEmptyString(turnMeaning?.asked_action_family),
action_family: toNonEmptyString(action),
aggregation_need: aggregationNeed,
time_scope_need: timeScopeNeed,
comparison_need: comparisonNeed,
@@ -109,10 +109,16 @@ function hasReasonCode(graph, reasonCode) {
function aggregationAxis(meaning) {
return toNonEmptyString(meaning?.asked_aggregation_axis)?.toLowerCase() ?? null;
}
function addScopeAxes(axes, meaning) {
function addScopeAxes(axes, meaning, graph) {
if (hasEntity(meaning)) {
pushUnique(axes, "counterparty");
}
if (hasSubjectCandidates(graph)) {
const factFamily = lower(graph?.business_fact_family);
if (factFamily === "value_flow" || factFamily === "activity_lifecycle") {
pushUnique(axes, "counterparty");
}
}
if (toNonEmptyString(meaning?.explicit_organization_scope)) {
pushUnique(axes, "organization");
}
@@ -498,7 +504,7 @@ function recipeFor(input) {
const combined = `${domain} ${action} ${unsupported}`.trim();
const axes = [];
const requestedAggregationAxis = aggregationAxis(meaning);
addScopeAxes(axes, meaning);
addScopeAxes(axes, meaning, dataNeedGraph);
addMetadataScopeAxis(axes, meaning);
addTimeScopeAxes(axes, dataNeedGraph);
if (graphClarificationGaps.includes("lane_family_choice")) {