NODEDC_1C/llm_normalizer/backend/dist/services/assistantMcpDiscoveryPilotE...

364 lines
15 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ASSISTANT_MCP_DISCOVERY_PILOT_EXECUTOR_SCHEMA_VERSION = void 0;
exports.executeAssistantMcpDiscoveryPilot = executeAssistantMcpDiscoveryPilot;
const addressMcpClient_1 = require("./addressMcpClient");
const assistantMcpDiscoveryRuntimeAdapter_1 = require("./assistantMcpDiscoveryRuntimeAdapter");
const assistantMcpDiscoveryPolicy_1 = require("./assistantMcpDiscoveryPolicy");
const addressRecipeCatalog_1 = require("./addressRecipeCatalog");
exports.ASSISTANT_MCP_DISCOVERY_PILOT_EXECUTOR_SCHEMA_VERSION = "assistant_mcp_discovery_pilot_executor_v1";
const DEFAULT_DEPS = {
executeAddressMcpQuery: addressMcpClient_1.executeAddressMcpQuery
};
function toNonEmptyString(value) {
if (value === null || value === undefined) {
return null;
}
const text = String(value).trim();
return text.length > 0 ? text : null;
}
function normalizeReasonCode(value) {
const normalized = value
.trim()
.replace(/[^\p{L}\p{N}_.:-]+/gu, "_")
.replace(/^_+|_+$/g, "")
.toLowerCase();
return normalized.length > 0 ? normalized.slice(0, 120) : null;
}
function pushReason(target, value) {
const normalized = normalizeReasonCode(value);
if (normalized && !target.includes(normalized)) {
target.push(normalized);
}
}
function pushUnique(target, value) {
const text = value.trim();
if (text && !target.includes(text)) {
target.push(text);
}
}
function firstEntityCandidate(planner) {
const candidates = planner.discovery_plan.turn_meaning_ref?.explicit_entity_candidates ?? [];
for (const candidate of candidates) {
const text = toNonEmptyString(candidate);
if (text) {
return text;
}
}
return null;
}
function dateScopeToFilters(dateScope) {
if (!dateScope) {
return {};
}
const yearMatch = dateScope.match(/^(\d{4})$/);
if (yearMatch) {
return {
period_from: `${yearMatch[1]}-01-01`,
period_to: `${yearMatch[1]}-12-31`
};
}
const dateMatch = dateScope.match(/^(\d{4})-(\d{2})-(\d{2})/);
if (dateMatch) {
const date = `${dateMatch[1]}-${dateMatch[2]}-${dateMatch[3]}`;
return {
period_from: date,
period_to: date
};
}
return {};
}
function buildLifecycleFilters(planner) {
const meaning = planner.discovery_plan.turn_meaning_ref;
const counterparty = firstEntityCandidate(planner);
const organization = toNonEmptyString(meaning?.explicit_organization_scope);
const dateScope = toNonEmptyString(meaning?.explicit_date_scope);
return {
...dateScopeToFilters(dateScope),
...(counterparty ? { counterparty } : {}),
...(organization ? { organization } : {}),
limit: planner.discovery_plan.execution_budget.max_rows_per_probe,
sort: "period_asc"
};
}
function isLifecyclePilotEligible(planner) {
const meaning = planner.discovery_plan.turn_meaning_ref;
const domain = String(meaning?.asked_domain_family ?? "").toLowerCase();
const action = String(meaning?.asked_action_family ?? "").toLowerCase();
const combined = `${domain} ${action}`;
return (planner.proposed_primitives.includes("query_documents") &&
(combined.includes("lifecycle") || combined.includes("activity") || combined.includes("duration") || combined.includes("age")));
}
function skippedProbeResult(step, limitation) {
return {
primitive_id: step.primitive_id,
status: "skipped",
rows_received: 0,
rows_matched: 0,
limitation
};
}
function queryResultToProbeResult(primitiveId, result) {
return {
primitive_id: primitiveId,
status: result.error ? "error" : "ok",
rows_received: result.fetched_rows,
rows_matched: result.matched_rows,
limitation: result.error
};
}
function summarizeRows(result) {
if (result.error) {
return null;
}
if (result.fetched_rows <= 0) {
return "0 MCP document rows fetched";
}
return `${result.fetched_rows} MCP document rows fetched, ${result.matched_rows} matched lifecycle scope`;
}
function rowDateValue(row) {
const candidates = [
row["Период"],
row["Period"],
row["period"],
row["Дата"],
row["Date"],
row["date"]
];
for (const candidate of candidates) {
const text = toNonEmptyString(candidate);
const match = text?.match(/(\d{4})-(\d{2})-(\d{2})/);
if (match) {
return `${match[1]}-${match[2]}-${match[3]}`;
}
}
return null;
}
function monthDiff(firstIsoDate, latestIsoDate) {
const first = new Date(`${firstIsoDate}T00:00:00.000Z`);
const latest = new Date(`${latestIsoDate}T00:00:00.000Z`);
if (Number.isNaN(first.getTime()) || Number.isNaN(latest.getTime()) || latest < first) {
return 0;
}
let months = (latest.getUTCFullYear() - first.getUTCFullYear()) * 12;
months += latest.getUTCMonth() - first.getUTCMonth();
if (latest.getUTCDate() < first.getUTCDate()) {
months -= 1;
}
return Math.max(0, months);
}
function formatDurationHumanRu(totalMonths) {
const years = Math.floor(totalMonths / 12);
const months = totalMonths % 12;
const parts = [];
if (years > 0) {
parts.push(`${years} ${years === 1 ? "год" : years >= 2 && years <= 4 ? "года" : "лет"}`);
}
if (months > 0) {
parts.push(`${months} ${months === 1 ? "месяц" : months >= 2 && months <= 4 ? "месяца" : "месяцев"}`);
}
return parts.length > 0 ? parts.join(" ") : "меньше месяца";
}
function deriveActivityPeriod(result) {
if (!result || result.error || result.matched_rows <= 0) {
return null;
}
const dates = result.rows
.map((row) => rowDateValue(row))
.filter((value) => Boolean(value))
.sort();
if (dates.length === 0) {
return null;
}
const first = dates[0];
const latest = dates[dates.length - 1];
const totalMonths = monthDiff(first, latest);
return {
first_activity_date: first,
latest_activity_date: latest,
matched_rows: result.matched_rows,
duration_total_months: totalMonths,
duration_years: Math.floor(totalMonths / 12),
duration_months_remainder: totalMonths % 12,
duration_human_ru: formatDurationHumanRu(totalMonths),
inference_basis: "first_and_latest_confirmed_1c_activity_rows"
};
}
function buildConfirmedFacts(result, counterparty) {
if (result.error || result.matched_rows <= 0) {
return [];
}
return [
counterparty
? `1C activity rows were found for counterparty ${counterparty}`
: "1C activity rows were found for the requested counterparty scope"
];
}
function buildInferredFacts(result) {
if (result.error || result.fetched_rows <= 0) {
return [];
}
return ["Business activity duration may be inferred from first and latest confirmed 1C activity rows"];
}
function buildUnknownFacts() {
return ["Legal registration date is not proven by this MCP discovery pilot"];
}
function buildEmptyEvidence(planner, dryRun, probeResults, reason) {
return (0, assistantMcpDiscoveryPolicy_1.resolveAssistantMcpDiscoveryEvidence)({
plan: planner.discovery_plan,
probeResults,
unknownFacts: [reason],
queryLimitations: [reason],
recommendedNextProbe: dryRun.user_facing_fallback
});
}
async function executeAssistantMcpDiscoveryPilot(planner, deps = DEFAULT_DEPS) {
const dryRun = (0, assistantMcpDiscoveryRuntimeAdapter_1.buildAssistantMcpDiscoveryRuntimeDryRun)(planner);
const reasonCodes = [...dryRun.reason_codes];
const executedPrimitives = [];
const skippedPrimitives = [];
const probeResults = [];
const queryLimitations = [];
if (dryRun.adapter_status === "blocked") {
pushReason(reasonCodes, "pilot_blocked_before_mcp_execution");
const evidence = buildEmptyEvidence(planner, dryRun, probeResults, "MCP discovery pilot was blocked before execution");
return {
schema_version: exports.ASSISTANT_MCP_DISCOVERY_PILOT_EXECUTOR_SCHEMA_VERSION,
policy_owner: "assistantMcpDiscoveryPilotExecutor",
pilot_status: "blocked",
pilot_scope: "counterparty_lifecycle_query_documents_v1",
dry_run: dryRun,
mcp_execution_performed: false,
executed_primitives: executedPrimitives,
skipped_primitives: skippedPrimitives,
probe_results: probeResults,
evidence,
source_rows_summary: null,
derived_activity_period: null,
query_limitations: ["MCP discovery pilot was blocked before execution"],
reason_codes: reasonCodes
};
}
if (dryRun.adapter_status !== "dry_run_ready") {
pushReason(reasonCodes, "pilot_needs_clarification_before_mcp_execution");
const evidence = buildEmptyEvidence(planner, dryRun, probeResults, "MCP discovery pilot needs more scope before execution");
return {
schema_version: exports.ASSISTANT_MCP_DISCOVERY_PILOT_EXECUTOR_SCHEMA_VERSION,
policy_owner: "assistantMcpDiscoveryPilotExecutor",
pilot_status: "skipped_needs_clarification",
pilot_scope: "counterparty_lifecycle_query_documents_v1",
dry_run: dryRun,
mcp_execution_performed: false,
executed_primitives: executedPrimitives,
skipped_primitives: skippedPrimitives,
probe_results: probeResults,
evidence,
source_rows_summary: null,
derived_activity_period: null,
query_limitations: ["MCP discovery pilot needs more scope before execution"],
reason_codes: reasonCodes
};
}
if (!isLifecyclePilotEligible(planner)) {
pushReason(reasonCodes, "pilot_scope_unsupported_for_live_execution");
for (const step of dryRun.execution_steps) {
skippedPrimitives.push(step.primitive_id);
probeResults.push(skippedProbeResult(step, "pilot_scope_unsupported_for_live_execution"));
}
const evidence = buildEmptyEvidence(planner, dryRun, probeResults, "MCP discovery pilot scope is not implemented yet");
return {
schema_version: exports.ASSISTANT_MCP_DISCOVERY_PILOT_EXECUTOR_SCHEMA_VERSION,
policy_owner: "assistantMcpDiscoveryPilotExecutor",
pilot_status: "unsupported",
pilot_scope: "counterparty_lifecycle_query_documents_v1",
dry_run: dryRun,
mcp_execution_performed: false,
executed_primitives: executedPrimitives,
skipped_primitives: skippedPrimitives,
probe_results: probeResults,
evidence,
source_rows_summary: null,
derived_activity_period: null,
query_limitations: ["MCP discovery pilot scope is not implemented yet"],
reason_codes: reasonCodes
};
}
let queryResult = null;
const counterparty = firstEntityCandidate(planner);
const filters = buildLifecycleFilters(planner);
const selection = (0, addressRecipeCatalog_1.selectAddressRecipe)("counterparty_activity_lifecycle", filters);
if (!selection.selected_recipe) {
pushReason(reasonCodes, "pilot_lifecycle_recipe_not_available");
const evidence = buildEmptyEvidence(planner, dryRun, probeResults, "Lifecycle recipe is not available");
return {
schema_version: exports.ASSISTANT_MCP_DISCOVERY_PILOT_EXECUTOR_SCHEMA_VERSION,
policy_owner: "assistantMcpDiscoveryPilotExecutor",
pilot_status: "unsupported",
pilot_scope: "counterparty_lifecycle_query_documents_v1",
dry_run: dryRun,
mcp_execution_performed: false,
executed_primitives: executedPrimitives,
skipped_primitives: skippedPrimitives,
probe_results: probeResults,
evidence,
source_rows_summary: null,
derived_activity_period: null,
query_limitations: ["Lifecycle recipe is not available"],
reason_codes: reasonCodes
};
}
const recipePlan = (0, addressRecipeCatalog_1.buildAddressRecipePlan)(selection.selected_recipe, filters);
for (const step of dryRun.execution_steps) {
if (step.primitive_id !== "query_documents") {
skippedPrimitives.push(step.primitive_id);
probeResults.push(skippedProbeResult(step, "pilot_only_executes_query_documents"));
continue;
}
queryResult = await deps.executeAddressMcpQuery({
query: recipePlan.query,
limit: recipePlan.limit,
account_scope: recipePlan.account_scope
});
executedPrimitives.push(step.primitive_id);
probeResults.push(queryResultToProbeResult(step.primitive_id, queryResult));
if (queryResult.error) {
pushUnique(queryLimitations, queryResult.error);
pushReason(reasonCodes, "pilot_query_documents_mcp_error");
}
else {
pushReason(reasonCodes, "pilot_query_documents_mcp_executed");
}
}
const sourceRowsSummary = queryResult ? summarizeRows(queryResult) : null;
const derivedActivityPeriod = deriveActivityPeriod(queryResult);
if (derivedActivityPeriod) {
pushReason(reasonCodes, "pilot_derived_activity_period_from_confirmed_rows");
}
const evidence = (0, assistantMcpDiscoveryPolicy_1.resolveAssistantMcpDiscoveryEvidence)({
plan: planner.discovery_plan,
probeResults,
confirmedFacts: queryResult ? buildConfirmedFacts(queryResult, counterparty) : [],
inferredFacts: queryResult ? buildInferredFacts(queryResult) : [],
unknownFacts: buildUnknownFacts(),
sourceRowsSummary,
queryLimitations,
recommendedNextProbe: "explain_evidence_basis"
});
return {
schema_version: exports.ASSISTANT_MCP_DISCOVERY_PILOT_EXECUTOR_SCHEMA_VERSION,
policy_owner: "assistantMcpDiscoveryPilotExecutor",
pilot_status: "executed",
pilot_scope: "counterparty_lifecycle_query_documents_v1",
dry_run: dryRun,
mcp_execution_performed: executedPrimitives.length > 0,
executed_primitives: executedPrimitives,
skipped_primitives: skippedPrimitives,
probe_results: probeResults,
evidence,
source_rows_summary: sourceRowsSummary,
derived_activity_period: derivedActivityPeriod,
query_limitations: queryLimitations,
reason_codes: reasonCodes
};
}