NODEDC_1C/llm_normalizer/backend/dist/services/assistantMcpDiscoveryAnswer...

166 lines
8.5 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.ASSISTANT_MCP_DISCOVERY_ANSWER_DRAFT_SCHEMA_VERSION = void 0;
exports.buildAssistantMcpDiscoveryAnswerDraft = buildAssistantMcpDiscoveryAnswerDraft;
exports.ASSISTANT_MCP_DISCOVERY_ANSWER_DRAFT_SCHEMA_VERSION = "assistant_mcp_discovery_answer_draft_v1";
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 uniqueStrings(values) {
const result = [];
for (const value of values) {
const text = String(value ?? "").trim();
if (text && !result.includes(text)) {
result.push(text);
}
}
return result;
}
function isInternalMechanicsLine(value) {
const text = value.toLowerCase();
return (text.includes("primitive") ||
text.includes("query_documents") ||
text.includes("query_movements") ||
text.includes("resolve_entity_reference") ||
text.includes("probe_coverage") ||
text.includes("explain_evidence_basis") ||
text.includes("pilot_only_executes") ||
text.includes("pilot_") ||
text.includes("runtime_") ||
text.includes("planner_") ||
text.includes("catalog_"));
}
function userFacingLimitations(values) {
return uniqueStrings(values).filter((value) => !isInternalMechanicsLine(value));
}
function modeFor(pilot) {
if (pilot.pilot_status === "blocked") {
return "blocked";
}
if (pilot.pilot_status === "skipped_needs_clarification") {
return "needs_clarification";
}
if (pilot.evidence.answer_permission === "confirmed_answer") {
return "confirmed_with_bounded_inference";
}
if (pilot.evidence.answer_permission === "bounded_inference") {
return "bounded_inference_only";
}
return "checked_sources_only";
}
function headlineFor(mode, pilot) {
if (pilot.derived_value_flow && mode === "confirmed_with_bounded_inference") {
return "По данным 1С найдены строки денежных движений; сумму можно называть только в рамках проверенного периода и найденных строк.";
}
if (mode === "confirmed_with_bounded_inference") {
return "По данным 1С есть подтвержденная активность; длительность можно оценивать только как вывод из этих строк.";
}
if (mode === "bounded_inference_only") {
return "Точный факт не подтвержден, но есть ограниченная оценка по найденной активности в 1С.";
}
if (mode === "needs_clarification") {
return "Нужно уточнить контекст перед поиском в 1С.";
}
if (mode === "blocked") {
return "Поиск в 1С заблокирован runtime-политикой до выполнения.";
}
return "Я проверил доступный контур, но подтвержденного факта для ответа не получил.";
}
function nextStepFor(mode, pilot) {
if (mode === "needs_clarification") {
return "Уточните контрагента, период или организацию, и я смогу выполнить проверку по 1С.";
}
if (mode === "checked_sources_only" && pilot.query_limitations.length > 0) {
return "Можно повторить проверку после восстановления MCP-доступа или сузить вопрос до конкретного контрагента/периода.";
}
if (mode === "blocked") {
return "Нужно сначала снять policy/blocking причину, иначе данные 1С использовать нельзя.";
}
return null;
}
function buildMustNotClaim(pilot) {
const claims = [
"Do not expose MCP primitive names, query text, debug ids, or internal execution mechanics in the user answer.",
"Do not claim rows were checked when mcp_execution_performed=false."
];
if (pilot.pilot_scope === "counterparty_lifecycle_query_documents_v1") {
claims.push("Do not claim legal registration age unless a legal registration source is confirmed.");
claims.push("Do not present inferred activity duration as a formally confirmed legal fact.");
}
if (pilot.pilot_scope === "counterparty_value_flow_query_movements_v1") {
claims.push("Do not claim full all-time turnover unless the checked period and coverage prove it.");
claims.push("Do not present a derived sum as a legal/accounting final total outside the checked 1C rows.");
}
if (pilot.evidence.confirmed_facts.length === 0) {
claims.push("Do not claim a confirmed business fact when confirmed_facts is empty.");
}
return claims;
}
function derivedActivityInferenceLine(pilot) {
const period = pilot.derived_activity_period;
if (!period) {
return null;
}
return [
`По подтвержденным строкам активности в 1С период взаимодействия можно оценить примерно как ${period.duration_human_ru}.`,
`Первая найденная активность: ${period.first_activity_date}; последняя найденная активность: ${period.latest_activity_date}.`,
"Это вывод по данным 1С, а не юридически подтвержденный возраст регистрации."
].join(" ");
}
function derivedValueFlowConfirmedLine(pilot) {
const flow = pilot.derived_value_flow;
if (!flow) {
return null;
}
const counterparty = flow.counterparty ? ` по контрагенту ${flow.counterparty}` : "";
const period = flow.period_scope ? ` за период ${flow.period_scope}` : " в проверенном окне";
const dates = flow.first_movement_date && flow.latest_movement_date
? ` Первая найденная дата движения: ${flow.first_movement_date}; последняя: ${flow.latest_movement_date}.`
: "";
return `По найденным строкам денежных движений в 1С${counterparty}${period} сумма составляет ${flow.total_amount_human_ru} Учтено строк с суммой: ${flow.rows_with_amount} из ${flow.rows_matched}.${dates} Это расчет по найденным строкам 1С, а не подтверждение полного оборота вне проверенного окна.`;
}
function buildAssistantMcpDiscoveryAnswerDraft(pilot) {
const mode = modeFor(pilot);
const reasonCodes = [...pilot.reason_codes, ...pilot.evidence.reason_codes];
pushReason(reasonCodes, `answer_mode_${mode}`);
if (pilot.evidence.unknown_facts.length > 0) {
pushReason(reasonCodes, "answer_contains_unknown_fact_boundary");
}
if (pilot.evidence.inferred_facts.length > 0) {
pushReason(reasonCodes, "answer_contains_bounded_inference");
}
const derivedInferenceLine = derivedActivityInferenceLine(pilot);
const inferenceLines = derivedInferenceLine
? [derivedInferenceLine]
: pilot.evidence.inferred_facts;
const derivedValueLine = derivedValueFlowConfirmedLine(pilot);
const confirmedLines = derivedValueLine
? [...pilot.evidence.confirmed_facts, derivedValueLine]
: pilot.evidence.confirmed_facts;
return {
schema_version: exports.ASSISTANT_MCP_DISCOVERY_ANSWER_DRAFT_SCHEMA_VERSION,
policy_owner: "assistantMcpDiscoveryAnswerAdapter",
answer_mode: mode,
headline: headlineFor(mode, pilot),
confirmed_lines: uniqueStrings(confirmedLines),
inference_lines: uniqueStrings(inferenceLines),
unknown_lines: uniqueStrings(pilot.evidence.unknown_facts),
limitation_lines: userFacingLimitations([...pilot.query_limitations, ...pilot.evidence.query_limitations]),
next_step_line: nextStepFor(mode, pilot),
internal_mechanics_allowed: false,
must_not_claim: buildMustNotClaim(pilot),
reason_codes: uniqueStrings(reasonCodes)
};
}