NODEDC_1C/llm_normalizer/backend/dist/services/routeHintAdapter.js

293 lines
13 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.simulateDeterministicRouting = simulateDeterministicRouting;
exports.toRouteHintSummary = toRouteHintSummary;
exports.toRouterInput = toRouterInput;
function toRouteHintSummaryV1(normalized) {
return {
mode: "legacy_v1",
intent_class: normalized.intent_class,
route_hint: normalized.route_hint,
confidence: normalized.confidence.route_hint,
decision_flags: {
needs_cross_entity_join: normalized.requires.needs_cross_entity_join,
needs_causal_chain: normalized.requires.needs_causal_chain,
needs_exact_object_trace: normalized.requires.needs_exact_object_trace,
needs_ranking: normalized.requires.needs_ranking,
needs_anomaly_summary: normalized.requires.needs_anomaly_summary,
needs_runtime_truth: normalized.requires.needs_runtime_truth,
needs_period_cut: normalized.requires.needs_period_cut,
needs_evidence: normalized.requires.needs_evidence
},
period_scope: normalized.period_scope,
entities: {
domain_entities: normalized.domain_entities,
accounts_mentioned: normalized.accounts_mentioned,
documents_mentioned: normalized.documents_mentioned,
registers_mentioned: normalized.registers_mentioned
}
};
}
function reasonForNoRoute(noRouteReason) {
if (noRouteReason === "out_of_scope") {
return "Fragment is out-of-scope for company-specific accounting contour.";
}
if (noRouteReason === "missing_mapping") {
return "Fragment is in-scope but route mapping is currently missing.";
}
if (noRouteReason === "unsupported_fragment_type") {
return "Fragment type is not supported by the current deterministic route map.";
}
return "Fragment requires clarification or is too underspecified for safe routing.";
}
function explicitRouteStatus(fragment) {
return "route_status" in fragment ? fragment.route_status : null;
}
function explicitNoRouteReason(fragment) {
return "no_route_reason" in fragment ? fragment.no_route_reason : null;
}
function executionReadiness(fragment) {
return "execution_readiness" in fragment ? fragment.execution_readiness : null;
}
function clarificationReason(fragment) {
return "clarification_reason" in fragment ? fragment.clarification_reason : null;
}
function softAssumptions(fragment) {
return "soft_assumption_used" in fragment ? fragment.soft_assumption_used : [];
}
function buildNoRouteDecision(fragment, noRouteReason) {
return {
fragment_id: fragment.fragment_id,
domain_relevance: fragment.domain_relevance,
business_scope: fragment.business_scope,
candidate_labels: fragment.candidate_labels,
decision_flags: fragment.flags,
execution_readiness: executionReadiness(fragment),
clarification_reason: clarificationReason(fragment),
soft_assumption_used: softAssumptions(fragment),
route_status: "no_route",
no_route_reason: noRouteReason ?? "insufficient_specificity",
route: "no_route",
reason: reasonForNoRoute(noRouteReason)
};
}
function decideRouteForFragment(fragment) {
const status = explicitRouteStatus(fragment);
const noRouteReason = explicitNoRouteReason(fragment);
const readiness = executionReadiness(fragment);
const clarification = clarificationReason(fragment);
const soft = softAssumptions(fragment);
if (status === "no_route") {
return buildNoRouteDecision(fragment, noRouteReason);
}
if (readiness === "needs_clarification" || readiness === "no_route") {
return buildNoRouteDecision(fragment, noRouteReason ?? "insufficient_specificity");
}
if (fragment.domain_relevance !== "in_scope") {
return buildNoRouteDecision(fragment, "out_of_scope");
}
if (fragment.flags.asks_for_exact_object_trace) {
return {
fragment_id: fragment.fragment_id,
domain_relevance: fragment.domain_relevance,
business_scope: fragment.business_scope,
candidate_labels: fragment.candidate_labels,
decision_flags: fragment.flags,
execution_readiness: readiness,
clarification_reason: clarification,
soft_assumption_used: soft,
route_status: "routed",
no_route_reason: null,
route: "live_mcp_drilldown",
reason: "Exact object trace requested."
};
}
if (fragment.flags.asks_for_ranking_or_top || fragment.flags.asks_for_period_summary) {
return {
fragment_id: fragment.fragment_id,
domain_relevance: fragment.domain_relevance,
business_scope: fragment.business_scope,
candidate_labels: fragment.candidate_labels,
decision_flags: fragment.flags,
execution_readiness: readiness,
clarification_reason: clarification,
soft_assumption_used: soft,
route_status: "routed",
no_route_reason: null,
route: "batch_refresh_then_store",
reason: "Ranking/summary semantics require batch analytical route."
};
}
if (fragment.flags.has_multi_entity_scope && fragment.flags.asks_for_chain_explanation) {
return {
fragment_id: fragment.fragment_id,
domain_relevance: fragment.domain_relevance,
business_scope: fragment.business_scope,
candidate_labels: fragment.candidate_labels,
decision_flags: fragment.flags,
execution_readiness: readiness,
clarification_reason: clarification,
soft_assumption_used: soft,
route_status: "routed",
no_route_reason: null,
route: "hybrid_store_plus_live",
reason: "Multi-entity causal chain requested."
};
}
if (fragment.flags.asks_for_rule_check && !fragment.flags.asks_for_chain_explanation) {
return {
fragment_id: fragment.fragment_id,
domain_relevance: fragment.domain_relevance,
business_scope: fragment.business_scope,
candidate_labels: fragment.candidate_labels,
decision_flags: fragment.flags,
execution_readiness: readiness,
clarification_reason: clarification,
soft_assumption_used: soft,
route_status: "routed",
no_route_reason: null,
route: "store_feature_risk",
reason: "Rule-control check without causal decomposition."
};
}
if (fragment.flags.asks_for_anomaly_scan &&
!fragment.flags.asks_for_ranking_or_top &&
!(fragment.flags.has_multi_entity_scope && fragment.flags.asks_for_chain_explanation)) {
return {
fragment_id: fragment.fragment_id,
domain_relevance: fragment.domain_relevance,
business_scope: fragment.business_scope,
candidate_labels: fragment.candidate_labels,
decision_flags: fragment.flags,
execution_readiness: readiness,
clarification_reason: clarification,
soft_assumption_used: soft,
route_status: "routed",
no_route_reason: null,
route: "store_feature_risk",
reason: "Anomaly scan without heavy ranking or causal chain."
};
}
if (status === "routed") {
return {
fragment_id: fragment.fragment_id,
domain_relevance: fragment.domain_relevance,
business_scope: fragment.business_scope,
candidate_labels: fragment.candidate_labels,
decision_flags: fragment.flags,
execution_readiness: readiness,
clarification_reason: clarification,
soft_assumption_used: soft,
route_status: "routed",
no_route_reason: null,
route: "store_canonical",
reason: "Routed fragment without deep analytical or causal signals."
};
}
return buildNoRouteDecision(fragment, "missing_mapping");
}
function fallbackMessageFor(type) {
if (type === "out_of_scope") {
return "Я работаю только с данными и бухгалтерским контуром текущей компании. Запрос вне доступной предметной области.";
}
if (type === "clarification") {
return "Могу проверить это в контуре компании, но нужно уточнить период, документ, счет или участок учета.";
}
if (type === "partial") {
return "Обработаю только часть запроса, которая относится к данным компании. Остальное выходит за пределы доступного контура.";
}
return null;
}
function simulateDeterministicRouting(normalized) {
const decisions = normalized.fragments.map((fragment) => decideRouteForFragment(fragment));
const inScopeCount = decisions.filter((item) => item.domain_relevance === "in_scope").length;
const outOfScopeCount = decisions.filter((item) => item.domain_relevance === "out_of_scope").length;
const routedInScopeCount = decisions.filter((item) => item.domain_relevance === "in_scope" && item.route !== "no_route").length;
const clarificationInScopeCount = decisions.filter((item) => item.domain_relevance === "in_scope" && item.execution_readiness === "needs_clarification").length;
const noRouteInScopeCount = decisions.filter((item) => item.domain_relevance === "in_scope" && item.route === "no_route").length;
let fallbackType = "none";
if (!normalized.message_in_scope || inScopeCount === 0) {
fallbackType = "out_of_scope";
}
else if (routedInScopeCount === 0 && clarificationInScopeCount > 0) {
fallbackType = "clarification";
}
else if (routedInScopeCount === 0 && noRouteInScopeCount > 0) {
fallbackType = "clarification";
}
else if ((inScopeCount > 0 && outOfScopeCount > 0) || (routedInScopeCount > 0 && noRouteInScopeCount > 0)) {
fallbackType = "partial";
}
return {
mode: "deterministic_v2",
message_in_scope: normalized.message_in_scope,
scope_confidence: normalized.scope_confidence,
planner: {
total_fragments: normalized.fragments.length,
in_scope_fragments: inScopeCount,
out_of_scope_fragments: outOfScopeCount,
discarded_fragments: normalized.discarded_fragments.length,
contains_multiple_tasks: normalized.contains_multiple_tasks
},
decisions,
fallback: {
type: fallbackType,
message: fallbackMessageFor(fallbackType)
}
};
}
function toRouteHintSummary(normalized) {
if (normalized.schema_version === "normalized_query_v2" ||
normalized.schema_version === "normalized_query_v2_0_1" ||
normalized.schema_version === "normalized_query_v2_0_2") {
return simulateDeterministicRouting(normalized);
}
return toRouteHintSummaryV1(normalized);
}
function toRouterInput(normalized) {
if (normalized.schema_version === "normalized_query_v2" ||
normalized.schema_version === "normalized_query_v2_0_1" ||
normalized.schema_version === "normalized_query_v2_0_2") {
return {
mode: "deterministic_v2",
message_in_scope: normalized.message_in_scope,
scope_confidence: normalized.scope_confidence,
contains_multiple_tasks: normalized.contains_multiple_tasks,
fragments: normalized.fragments.map((fragment) => ({
fragment_id: fragment.fragment_id,
domain_relevance: fragment.domain_relevance,
business_scope: fragment.business_scope,
execution_readiness: "execution_readiness" in fragment ? fragment.execution_readiness : null,
clarification_reason: "clarification_reason" in fragment ? fragment.clarification_reason : null,
soft_assumption_used: "soft_assumption_used" in fragment ? fragment.soft_assumption_used : [],
route_status: "route_status" in fragment ? fragment.route_status : null,
no_route_reason: "no_route_reason" in fragment ? fragment.no_route_reason : null,
flags: fragment.flags,
candidate_labels: fragment.candidate_labels,
confidence: fragment.confidence
}))
};
}
return {
mode: "legacy_v1",
intent_class: normalized.intent_class,
decision_flags: {
needs_cross_entity_join: normalized.requires.needs_cross_entity_join,
needs_causal_chain: normalized.requires.needs_causal_chain,
needs_exact_object_trace: normalized.requires.needs_exact_object_trace,
needs_ranking: normalized.requires.needs_ranking,
needs_anomaly_summary: normalized.requires.needs_anomaly_summary,
needs_runtime_truth: normalized.requires.needs_runtime_truth
},
route_hint: normalized.route_hint,
confidence: normalized.confidence.overall,
entities: {
domain_entities: normalized.domain_entities,
accounts_mentioned: normalized.accounts_mentioned,
documents_mentioned: normalized.documents_mentioned,
registers_mentioned: normalized.registers_mentioned
},
period_scope: normalized.period_scope
};
}