Stage_04_Wave_15_Question_Type_Contract_First_Check_Relevance

This commit is contained in:
2026-03-28 14:09:08 +03:00
parent 8b84f5e989
commit 014ff65188
8 changed files with 952 additions and 115 deletions
+203 -24
View File
@@ -2519,12 +2519,27 @@ function extractRequirementIdsFromText(value) {
const matches = String(value ?? "").match(/\bR\d+\b/gi);
return uniqueStrings((matches ?? []).map((item) => item.toUpperCase()), 8);
}
function buildCoverageSplitLines(structure) {
function buildCoverageSplitLines(structure, questionType = "unknown") {
const confirmed = uniqueStrings((structure.evidence_block.claim_evidence_links ?? [])
.flatMap((item) => extractRequirementIdsFromText(item.claim_ref))
.map((item) => item.toUpperCase()), 8);
const unresolved = uniqueStrings(structure.uncertainty_block.open_uncertainties.flatMap((item) => extractRequirementIdsFromText(item)), 8);
const lines = [];
if (questionType === "which_chains_are_complete_vs_incomplete") {
if (confirmed.length > 0) {
lines.push(`Цепочки подтверждены: ${confirmed.join(", ")}.`);
}
if (unresolved.length > 0) {
lines.push(`Цепочки подтверждены частично или не подтверждены: ${unresolved.join(", ")}.`);
}
else if (structure.evidence_block.coverage_note === "coverage_partial_or_limited") {
lines.push("Часть цепочек подтверждена частично; для остальных не хватает опоры.");
}
if (lines.length === 0) {
lines.push("Цепочки пока не удалось уверенно разделить на полные и неполные.");
}
return dedupeNarrativeLines(lines, 3);
}
if (confirmed.length > 0) {
lines.push(`Подтверждено по требованиям: ${confirmed.join(", ")}.`);
}
@@ -2536,7 +2551,7 @@ function buildCoverageSplitLines(structure) {
}
return dedupeNarrativeLines(lines, 3);
}
function buildEvidenceSectionLines(structure) {
function buildEvidenceSectionLines(structure, questionType = "unknown") {
const evidenceCount = Array.isArray(structure.evidence_block.evidence_ids) ? structure.evidence_block.evidence_ids.length : 0;
const sourceCount = Array.isArray(structure.evidence_block.source_refs) ? structure.evidence_block.source_refs.length : 0;
const claimLinks = Array.isArray(structure.evidence_block.claim_evidence_links)
@@ -2547,7 +2562,16 @@ function buildEvidenceSectionLines(structure) {
structure.uncertainty_block.open_uncertainties.length > 0 ||
structure.evidence_block.coverage_note === "coverage_partial_or_limited";
const lines = [];
const coverageSplitLines = buildCoverageSplitLines(structure);
const coverageSplitLines = buildCoverageSplitLines(structure, questionType);
if (questionType === "what_is_it_grounded_on") {
lines.push("Основание вывода перечислено по подтвержденным документам, регистрам и проводкам.");
}
else if (questionType === "prove_or_guess") {
lines.push("Основание разделено на подтвержденную часть и зону гипотез.");
}
else if (questionType === "which_chains_are_complete_vs_incomplete") {
lines.push("Опора собрана так, чтобы разделить цепочки на полные и неполные.");
}
if (evidenceCount > 0) {
lines.push(`Вывод опирается на ${evidenceCount} подтвержденных наблюдений в текущем срезе.`);
}
@@ -2589,7 +2613,111 @@ function buildDefaultChecksByDomain(domain) {
}
return ["Проверьте связку документов и проводок по проблемному участку в указанном периоде."];
}
function buildChecksSectionLines(structure) {
function buildQuestionTypeDomainChecks(questionType, domain) {
if (questionType === "what_to_check_first") {
if (domain === "settlements_60_62") {
return [
"Сверьте договор и объект расчетов по спорной операции.",
"Проверьте регистр расчетов и зачет аванса/взаимозачет.",
"Подтвердите проводки по 60/62/76 и факт закрытия хвоста."
];
}
if (domain === "vat_document_register_book") {
return [
"Сверьте исходный документ и счет-фактуру.",
"Проверьте запись в регистре НДС и попадание в книгу.",
"Подтвердите налоговые проводки по 19/68 в нужном периоде."
];
}
if (domain === "month_close_costs_20_44") {
return [
"Проверьте регламентную операцию закрытия за нужный период.",
"Сверьте базу распределения затрат и проводки по 20/25/26/44.",
"Убедитесь, что остатки объяснены или закрыты после операции."
];
}
return ["Начните с первого подтверждаемого документа и пройдите цепочку без пропусков."];
}
if (questionType === "where_break_is") {
if (domain === "settlements_60_62") {
return [
"Локализуйте разрыв в узле: договор -> объект расчетов -> регистр расчетов -> закрывающий документ.",
"Сверьте, где прерывается переход платеж -> зачет/закрытие -> проводки 60/62/76."
];
}
if (domain === "vat_document_register_book") {
return [
"Локализуйте разрыв в узле: документ -> счет-фактура -> регистр НДС -> книга.",
"Сверьте, где прерывается переход от исходного документа к налоговой записи."
];
}
if (domain === "month_close_costs_20_44") {
return [
"Локализуйте разрыв в узле: накопление затрат -> правило распределения -> операция закрытия.",
"Сверьте, на каком шаге исчезает подтверждение перехода к закрытию остатков."
];
}
}
if (questionType === "prove_or_guess") {
if (domain === "settlements_60_62") {
return [
"Отдельно отметьте, что доказано документами и проводками, а что остается гипотезой.",
"Для доказательства проверьте связку платеж -> расчетный документ -> регистр расчетов -> 60/62/76."
];
}
if (domain === "vat_document_register_book") {
return [
"Разделите доказанное и предположительное по цепочке: документ -> счет-фактура -> регистр -> книга.",
"Подтвердите налоговую запись по 19/68 в нужном периоде."
];
}
if (domain === "month_close_costs_20_44") {
return [
"Разделите доказанные и предположительные участки в цепочке закрытия месяца.",
"Проверьте подтверждение: операция закрытия -> распределение -> остатки по 20/25/26/44."
];
}
}
if (questionType === "what_is_it_grounded_on") {
if (domain === "settlements_60_62") {
return [
"Перечислите основание: платежный документ, расчетный документ, запись регистра расчетов, проводки 60/62/76."
];
}
if (domain === "vat_document_register_book") {
return [
"Перечислите основание: исходный документ, счет-фактура, запись регистра НДС, запись книги, проводки 19/68."
];
}
if (domain === "month_close_costs_20_44") {
return [
"Перечислите основание: операция закрытия, база распределения, проводки по затратам, остатки после закрытия."
];
}
}
if (questionType === "which_chains_are_complete_vs_incomplete") {
if (domain === "settlements_60_62") {
return [
"Разделите цепочки на: подтверждена, подтверждена частично, не подтверждена по переходу платеж -> закрытие расчета.",
"Проверьте разницу между закрытыми и незакрытыми связками по 60/62/76."
];
}
if (domain === "vat_document_register_book") {
return [
"Разделите цепочки на: полная, частичная, неполная по связке документ -> счет-фактура -> регистр -> книга.",
"Проверьте, где отсутствует подтверждение налоговой записи."
];
}
if (domain === "month_close_costs_20_44") {
return [
"Разделите цепочки закрытия на полные и неполные по шагам распределения и регламентной операции.",
"Проверьте, какие остатки после закрытия подтверждены, а какие нет."
];
}
}
return buildDefaultChecksByDomain(domain);
}
function buildChecksSectionLines(structure, context) {
const actionLines = dedupeNarrativeLines([
...structure.next_step_block.recommended_actions,
...structure.next_step_block.clarification_questions
@@ -2601,29 +2729,49 @@ function buildChecksSectionLines(structure) {
.filter((item) => item.length >= 18)
.filter((item) => !/\b(?:factual|source-of-record|reference)\b/i.test(item)), 4);
const broken = sanitizeUserText(structure.direct_answer) ?? "";
const domain = inferNarrativeDomainFromText(broken);
const domainFallback = buildDefaultChecksByDomain(domain);
const domain = context?.focusDomain ?? inferNarrativeDomainFromText(broken);
const questionType = context?.questionType ?? "unknown";
const domainFallback = buildQuestionTypeDomainChecks(questionType, domain);
const hasMissingPeriod = structure.uncertainty_block.open_uncertainties.some((item) => /missing_anchor:period/i.test(String(item ?? "")));
const lines = [];
if (domain === "settlements_60_62") {
lines.push(...domainFallback.slice(0, 2));
lines.push(...actionLines.slice(0, 2));
if (questionType === "what_to_check_first") {
lines.push(...domainFallback.slice(0, 3));
if (lines.length < 3) {
lines.push(...actionLines.slice(0, 3 - lines.length));
}
}
else if (actionLines.length > 0) {
else if (questionType === "what_is_it_grounded_on") {
lines.push(...domainFallback.slice(0, 2));
lines.push(...actionLines.slice(0, 1));
}
else if (questionType === "prove_or_guess" || questionType === "where_break_is") {
lines.push(...domainFallback.slice(0, 2));
lines.push(...actionLines.slice(0, 2));
}
else {
lines.push(...domainFallback.slice(0, 2));
if (domain === "settlements_60_62") {
lines.push(...domainFallback.slice(0, 2));
lines.push(...actionLines.slice(0, 2));
}
else if (actionLines.length > 0) {
lines.push(...actionLines.slice(0, 2));
}
else {
lines.push(...domainFallback.slice(0, 2));
}
}
if (hasMissingPeriod) {
if (domain === "settlements_60_62" && lines.length > 0) {
if (questionType === "what_to_check_first") {
lines.push("Уточните период, если он не зафиксирован в исходной формулировке вопроса.");
}
else if (domain === "settlements_60_62" && lines.length > 0) {
lines.push("Уточните период проверки, чтобы подтвердить проблему без лишнего шума.");
}
else {
lines.unshift("Уточните период проверки, чтобы подтвердить проблему без лишнего шума.");
}
}
return dedupeNarrativeLines(lines, 4);
return dedupeNarrativeLines(lines, questionType === "what_to_check_first" ? 3 : 5);
}
function humanizeLimitationToken(value) {
const raw = String(value ?? "").trim();
@@ -2719,19 +2867,19 @@ function domainNameForQuestionType(domain) {
function buildQuestionTypeShortLine(context) {
const domainName = domainNameForQuestionType(context.focusDomain);
if (context.questionType === "where_break_is") {
return `\u041f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442 \u043e\u0442\u0432\u0435\u0442\u0430: \u043b\u043e\u043a\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0440\u0430\u0437\u0440\u044b\u0432 \u0432\u043d\u0443\u0442\u0440\u0438 ${domainName}.`;
return `\u041b\u043e\u043a\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0432\u0435\u0440\u043e\u044f\u0442\u043d\u044b\u0439 \u0443\u0437\u0435\u043b \u0440\u0430\u0437\u0440\u044b\u0432\u0430 \u0432\u043d\u0443\u0442\u0440\u0438 ${domainName}.`;
}
if (context.questionType === "prove_or_guess") {
return "\u041f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442 \u043e\u0442\u0432\u0435\u0442\u0430: \u0440\u0430\u0437\u0432\u0435\u0441\u0442\u0438 \u0434\u043e\u043a\u0430\u0437\u0430\u043d\u043e \u0438 \u0433\u0438\u043f\u043e\u0442\u0435\u0437\u0443.";
return "\u0412\u044b\u0432\u043e\u0434 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d \u043d\u0430 \u0434\u043e\u043a\u0430\u0437\u0430\u043d\u043d\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u0438 \u0433\u0438\u043f\u043e\u0442\u0435\u0437\u0443.";
}
if (context.questionType === "what_is_it_grounded_on") {
return "\u041f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442 \u043e\u0442\u0432\u0435\u0442\u0430: \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u044b\u0432\u043e\u0434\u0430 \u043f\u043e \u0434\u0430\u043d\u043d\u044b\u043c.";
return "\u041d\u0438\u0436\u0435 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u044b \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u044b\u0432\u043e\u0434\u0430 \u043f\u043e \u0434\u0430\u043d\u043d\u044b\u043c \u0443\u0447\u0435\u0442\u0430.";
}
if (context.questionType === "which_chains_are_complete_vs_incomplete") {
return "\u041f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442 \u043e\u0442\u0432\u0435\u0442\u0430: \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u044b\u0435 \u0438 \u043d\u0435\u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u044b\u0435 \u0446\u0435\u043f\u043e\u0447\u043a\u0438.";
return "\u0426\u0435\u043f\u043e\u0447\u043a\u0438 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u044b \u043d\u0430 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u043d\u044b\u0435, \u0447\u0430\u0441\u0442\u0438\u0447\u043d\u043e \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u043d\u044b\u0435 \u0438 \u043d\u0435\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u043d\u044b\u0435.";
}
if (context.questionType === "what_to_check_first") {
return "\u041f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442 \u043e\u0442\u0432\u0435\u0442\u0430: \u0434\u0430\u0442\u044c \u043f\u0435\u0440\u0432\u044b\u0439 \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438.";
return `\u041a\u043e\u0440\u043e\u0442\u043a\u0438\u0439 \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u043f\u0435\u0440\u0432\u044b\u0445 \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a \u0432\u043d\u0443\u0442\u0440\u0438 ${domainName}.`;
}
return null;
}
@@ -2751,12 +2899,18 @@ function buildQuestionTypeBrokenLine(context) {
return "\u0412\u0435\u0440\u043e\u044f\u0442\u043d\u044b\u0439 \u0443\u0437\u0435\u043b \u0440\u0430\u0437\u0440\u044b\u0432\u0430 \u043b\u043e\u043a\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d \u0447\u0430\u0441\u0442\u0438\u0447\u043d\u043e; \u043d\u0443\u0436\u043d\u0430 \u0442\u043e\u0447\u0435\u0447\u043d\u0430\u044f \u0441\u0432\u0435\u0440\u043a\u0430.";
}
function buildQuestionTypeWhyLine(context) {
if (context.questionType === "where_break_is") {
return "\u0424\u043e\u043a\u0443\u0441 \u043e\u0442\u0432\u0435\u0442\u0430: \u043d\u0435 \u043e\u0431\u0449\u0438\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c, \u0430 \u0442\u043e\u0447\u043a\u0430 \u0440\u0430\u0437\u0440\u044b\u0432\u0430 \u0432 \u0446\u0435\u043f\u043e\u0447\u043a\u0435.";
}
if (context.questionType === "prove_or_guess") {
return "\u0417\u0434\u0435\u0441\u044c \u0447\u0435\u0441\u0442\u043d\u043e \u0440\u0430\u0437\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0447\u0442\u043e \u0443\u0436\u0435 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u043e \u0438 \u0447\u0442\u043e \u043f\u043e\u043a\u0430 \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u0433\u0438\u043f\u043e\u0442\u0435\u0437\u043e\u0439.";
return "\u041e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e, \u0447\u0442\u043e \u0443\u0436\u0435 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u043e, \u0430 \u0447\u0442\u043e \u043f\u043e\u043a\u0430 \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u0433\u0438\u043f\u043e\u0442\u0435\u0437\u043e\u0439.";
}
if (context.questionType === "which_chains_are_complete_vs_incomplete") {
return "\u0426\u0435\u043f\u043e\u0447\u043a\u0438 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u044b \u043d\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u044b\u0435 \u0438 \u043d\u0435\u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u044b\u0435 \u043f\u043e \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u043e\u043f\u043e\u0440\u0435.";
}
if (context.questionType === "what_is_it_grounded_on") {
return "\u0424\u043e\u043a\u0443\u0441 \u043e\u0442\u0432\u0435\u0442\u0430 \u0441\u043c\u0435\u0449\u0435\u043d \u0432 \u0434\u043e\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0438, \u0430 \u043d\u0435 \u0432 \u043e\u0431\u0449\u0438\u0439 narrative.";
}
return null;
}
function buildQuestionTypeEvidenceLine(context) {
@@ -2766,6 +2920,9 @@ function buildQuestionTypeEvidenceLine(context) {
if (context.questionType === "prove_or_guess") {
return "\u0421\u0438\u043b\u0430 \u0432\u044b\u0432\u043e\u0434\u0430 \u043e\u0446\u0435\u043d\u0435\u043d\u0430 \u043f\u043e \u043f\u0440\u044f\u043c\u043e\u0439 \u043e\u043f\u043e\u0440\u0435, \u0430 \u043d\u0435 \u043f\u043e \u0434\u043e\u0433\u0430\u0434\u043a\u0430\u043c.";
}
if (context.questionType === "which_chains_are_complete_vs_incomplete") {
return "\u041e\u043f\u043e\u0440\u0430 \u0441\u043e\u0431\u0440\u0430\u043d\u0430 \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u0447\u0435\u0441\u0442\u043d\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u043f\u043e\u043b\u043d\u044b\u0435 \u0438 \u043d\u0435\u043f\u043e\u043b\u043d\u044b\u0435 \u0446\u0435\u043f\u043e\u0447\u043a\u0438.";
}
return null;
}
function formatAnchorList(anchors, prefix) {
@@ -2776,7 +2933,19 @@ function formatAnchorList(anchors, prefix) {
}
function buildQuestionTypeCheckLine(context) {
if (context.questionType === "what_to_check_first") {
return "\u041d\u0430\u0447\u043d\u0438\u0442\u0435 \u0441 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u043f\u0443\u043d\u043a\u0442\u0430 \u0438 \u043f\u0440\u043e\u0439\u0434\u0438\u0442\u0435 \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u0431\u0435\u0437 \u043f\u0435\u0440\u0435\u0441\u043a\u043e\u043a\u0430.";
return "\u041f\u0440\u043e\u0432\u0435\u0440\u044c\u0442\u0435 \u043f\u0443\u043d\u043a\u0442\u044b \u043f\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0443: \u0448\u0430\u0433 1 -> \u0448\u0430\u0433 2 -> \u0448\u0430\u0433 3.";
}
if (context.questionType === "where_break_is") {
return "\u041b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0440\u0430\u0437\u0440\u044b\u0432\u0430 \u043d\u0430\u0447\u043d\u0438\u0442\u0435 \u0441 \u0443\u0437\u043b\u0430, \u0433\u0434\u0435 \u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043b \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u0442\u044c\u0441\u044f.";
}
if (context.questionType === "prove_or_guess") {
return "\u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435\u043c \u043e\u0442\u0434\u0435\u043b\u0438\u0442\u0435 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u043e \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u043d\u044b\u0435 \u0444\u0430\u043a\u0442\u044b \u043e\u0442 \u0433\u0438\u043f\u043e\u0442\u0435\u0437.";
}
if (context.questionType === "what_is_it_grounded_on") {
return "\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0438\u0442\u0435 \u043e\u043f\u043e\u0440\u043d\u044b\u0435 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u044b \u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u044b, \u0437\u0430\u0442\u0435\u043c \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u044e\u0449\u0438\u0435 \u043f\u0440\u043e\u0432\u043e\u0434\u043a\u0438.";
}
if (context.questionType === "which_chains_are_complete_vs_incomplete") {
return "\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0440\u0430\u0437\u043b\u043e\u0436\u0438\u0442\u0435 \u0446\u0435\u043f\u043e\u0447\u043a\u0438 \u043d\u0430 \u043f\u043e\u043b\u043d\u044b\u0435, \u0447\u0430\u0441\u0442\u0438\u0447\u043d\u043e \u043f\u043e\u043b\u043d\u044b\u0435 \u0438 \u043d\u0435\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u043d\u044b\u0435.";
}
return null;
}
@@ -2787,6 +2956,15 @@ function buildQuestionTypeLimitationLine(context) {
if (context.questionType === "which_chains_are_complete_vs_incomplete") {
return "\u0414\u0435\u043b\u0435\u043d\u0438\u0435 \u043d\u0430 \u00abcomplete/incomplete\u00bb \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u043f\u043e\u043b\u043d\u043e\u0442\u044b \u0446\u0435\u043f\u043e\u0447\u043a\u0438 \u0432 \u0442\u0435\u043a\u0443\u0449\u0435\u043c \u0441\u0440\u0435\u0437\u0435.";
}
if (context.questionType === "where_break_is") {
return "\u0422\u043e\u0447\u043d\u0430\u044f \u043b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043c\u043e\u0436\u0435\u0442 \u0441\u043c\u0435\u0449\u0430\u0442\u044c\u0441\u044f, \u0435\u0441\u043b\u0438 \u0447\u0430\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u043e\u0432 \u0432 \u0446\u0435\u043f\u043e\u0447\u043a\u0435 \u043d\u0435 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0430.";
}
if (context.questionType === "what_is_it_grounded_on") {
return "\u0412 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u043d\u044b\u0435 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0438; \u043d\u0435\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u043d\u044b\u0435 \u0432\u044b\u043d\u0435\u0441\u0435\u043d\u044b \u0432 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f.";
}
if (context.questionType === "what_to_check_first") {
return "\u041c\u0430\u0440\u0448\u0440\u0443\u0442 \u043f\u0435\u0440\u0432\u0438\u0447\u043d\u044b\u0439 \u0438 \u043c\u043e\u0436\u0435\u0442 \u0443\u0442\u043e\u0447\u043d\u044f\u0442\u044c\u0441\u044f \u043f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0448\u0430\u0433\u0430.";
}
return null;
}
function applyQuestionTypeAndAnchorPolicy(input) {
@@ -2795,8 +2973,8 @@ function applyQuestionTypeAndAnchorPolicy(input) {
const nextWhy = dedupeNarrativeLines([buildQuestionTypeWhyLine(input.context), ...input.whyLines].filter((item) => Boolean(item)), 4);
const anchorUsedLine = formatAnchorList(input.context.anchors.used, "\u0412 \u043e\u043f\u043e\u0440\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u044b \u044f\u043a\u043e\u0440\u044f \u0432\u043e\u043f\u0440\u043e\u0441\u0430");
const anchorUnusedLine = formatAnchorList(input.context.anchors.unused, "\u042f\u043a\u043e\u0440\u044f \u0438\u0437 \u0432\u043e\u043f\u0440\u043e\u0441\u0430 \u0431\u0435\u0437 \u043f\u0440\u044f\u043c\u043e\u0433\u043e \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f");
const nextEvidence = dedupeNarrativeLines([buildQuestionTypeEvidenceLine(input.context), ...input.evidenceLines, anchorUsedLine].filter((item) => Boolean(item)), 7);
const nextChecks = dedupeNarrativeLines([buildQuestionTypeCheckLine(input.context), ...input.checkLines].filter((item) => Boolean(item)), 5);
const nextEvidence = dedupeNarrativeLines([buildQuestionTypeEvidenceLine(input.context), ...input.evidenceLines, anchorUsedLine].filter((item) => Boolean(item)), input.context.questionType === "what_to_check_first" ? 4 : 7);
const nextChecks = dedupeNarrativeLines([buildQuestionTypeCheckLine(input.context), ...input.checkLines].filter((item) => Boolean(item)), input.context.questionType === "what_to_check_first" ? 3 : 5);
const nextLimitations = dedupeNarrativeLines([buildQuestionTypeLimitationLine(input.context), anchorUnusedLine, ...input.limitationLines].filter((item) => Boolean(item)), 6);
return {
shortLine: ensureSentence(nextShort),
@@ -2808,11 +2986,12 @@ function applyQuestionTypeAndAnchorPolicy(input) {
};
}
function renderPolicyReply(structure, context) {
const questionType = context?.questionType ?? "unknown";
const shortLine = ensureSentence(buildShortSectionLine(structure));
const brokenLines = buildBrokenSectionLines(structure);
const whyLines = buildWhySectionLines(structure);
const evidenceLines = buildEvidenceSectionLines(structure);
const checkLines = buildChecksSectionLines(structure);
const evidenceLines = buildEvidenceSectionLines(structure, questionType);
const checkLines = buildChecksSectionLines(structure, context);
const limitationLines = buildLimitationsSectionLines(structure);
const enriched = context
? applyQuestionTypeAndAnchorPolicy({
+67 -18
View File
@@ -4,40 +4,89 @@ exports.resolveQuestionType = resolveQuestionType;
const QUESTION_TYPE_RULES = [
{
type: "what_to_check_first",
pattern: /(?:\bwhat\s+to\s+check\s+first\b|\bfirst\s+check\b|\bcheck\s+first\b|\u0441\s+\u0447\u0435\u0433\u043e\s+\u043d\u0430\u0447\u0430\u0442\u044c\s+\u043f\u0440\u043e\u0432\u0435\u0440\u043a|\u0447\u0442\u043e\s+\u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c\s+\u043f\u0435\u0440\u0432)/iu
},
{
type: "what_is_it_grounded_on",
pattern: /(?:\bwhat\s+is\s+it\s+grounded\s+on\b|\bgrounded\s+on\b|\bbased\s+on\b|\bwhat\s+evidence\b|\u043d\u0430\s+\u0447(?:\u0435|\u0451)\u043c\s+\u044d\u0442\u043e\s+\u043e\u0441\u043d\u043e\u0432\u0430\u043d|\u0447\u0435\u043c\s+\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434)/iu
},
{
type: "prove_or_guess",
pattern: /(?:\bprove\b|\bguess\b|\bprove\s+or\s+guess\b|\bis\s+it\s+proven\b|\u044d\u0442\u043e\s+\u0434\u043e\u043a\u0430\u0437\u0430\u043d|\u0438\u043b\u0438\s+\u0442\u043e\u043b\u044c\u043a\u043e\s+\u0433\u0438\u043f\u043e\u0442\u0435\u0437|\u0434\u043e\u043a\u0430\u0437\u0430\u043d|\u0434\u043e\u0433\u0430\u0434|\u0435\u0441\u0442\u044c\s+\u043b\u0438|\u043c\u043e\u0436\u0435\u0442\s+\u043b\u0438|\u044d\u0442\u043e\s+\u0443\u0436\u0435.*\u0438\u043b\u0438)/iu
},
{
type: "which_chains_are_complete_vs_incomplete",
pattern: /(?:\bcomplete(?:d)?\b.*\bincomplete\b|\bwhich\s+chains?\b|\bcomplete\s+vs\s+incomplete\b|\u043a\u0430\u043a\u0438\u0435\s+\u0446\u0435\u043f\u043e\u0447\u043a[аи]\s+.*\u0437\u0430\u0432\u0435\u0440\u0448|\u0447\u0442\u043e\s+\u0437\u0430\u043a\u0440\u044b\u0442\u043e.*\u0447\u0442\u043e\s+\u043d\u0435\u0442)/iu
priority: 1,
patterns: [
/(?:\bwhat\s+to\s+check\s+first\b|\bfirst\s+check\b|\bcheck\s+first\b)/iu,
/(?:что\s+проверить\s+перв(?:ым|ой)|с\s+чего\s+начать\s+проверк|перв(?:ый|ым)\s+шаг(?:ом)?\s+проверк)/iu
]
},
{
type: "where_break_is",
pattern: /(?:\bwhere\s+is\s+the\s+break\b|\bwhere\s+exactly\b|\blocate\b|\u0433\u0434\u0435\s+\u0438\u043c\u0435\u043d\u043d\u043e|\u0433\u0434\u0435\s+\u0440\u0430\u0437\u0440\u044b\u0432|\u0432\s+\u043a\u0430\u043a\u043e\u043c\s+\u043c\u0435\u0441\u0442\u0435)/iu
priority: 2,
patterns: [
/(?:\bwhere\s+is\s+the\s+break\b|\bwhere\s+exactly\b|\blocate(?:\s+the\s+break)?\b)/iu,
/(?:где\s+именно|где\s+разрыв|в\s+каком\s+месте|на\s+каком\s+этапе|локализ(?:овать|аци)|какой\s+узел)/iu
]
},
{
type: "which_chains_are_complete_vs_incomplete",
priority: 3,
patterns: [
/(?:\bcomplete(?:d)?\b.*\bincomplete\b|\bwhich\s+chains?\b|\bcomplete\s+vs\s+incomplete\b)/iu,
/(?:какие(?:\s+\S+){0,4}\s+цепочк[аи].*(?:заверш|полны|неполны|не\s+заверш|подтвержд)|что\s+закрыто.*что\s+нет)/iu,
/(?:цепочк[аи].*(?:полная|неполная|частич|выпадени)|отраж[её]н\s+частич.*документ.*сч[её]т[-\s]?фактур)/iu
]
},
{
type: "prove_or_guess",
priority: 4,
patterns: [
/(?:\bprove\b|\bguess\b|\bprove\s+or\s+guess\b|\bis\s+it\s+proven\b)/iu,
/(?:это\s+доказан|докаж(?:и|ите|ите\s+ли)|доказуем|доказательн|гипотез|догад(?:ка|ыв))/iu,
/(?:доказано\s+или\s+нет|похоже\s+или\s+доказано|зач[её]л(?:ся|ось)\s+ли|связан\s+ли|вс[её]\s+ли.*закрыл|больше\s+похоже.*или)/iu,
/(?:это\s+уже\s+[^?!.]{3,}\s+или|есть\s+ли\s+[^?!.]{0,80}ситуац[^?!.]{0,80}\s+где)/iu
]
},
{
type: "what_is_it_grounded_on",
priority: 5,
patterns: [
/(?:\bwhat\s+is\s+it\s+grounded\s+on\b|\bgrounded\s+on\b|\bbased\s+on\b|\bwhat\s+evidence\b)/iu,
/(?:на\s+ч(?:е|ё)м[^?!.]{0,40}основан|чем\s+подтвержда(?:ется|но)|какие\s+основани[яе]|какими\s+доказательств)/iu,
/(?:есть\s+ли\s+[^?!.]{0,80}признак[аи])/iu
]
},
{
type: "why_breaks",
pattern: /(?:\bwhy\b|\bwhy\s+does\s+it\s+break\b|\u043f\u043e\u0447\u0435\u043c\u0443|\u0432\s+\u0447(?:\u0435|\u0451)\u043c\s+\u043f\u0440\u0438\u0447\u0438\u043d\u0430|\u0438\u0437-\u0437\u0430\s+\u0447\u0435\u0433\u043e)/iu
priority: 6,
patterns: [
/(?:\bwhy\b|\bwhy\s+does\s+it\s+break\b|\bwhat\s+causes\b)/iu,
/(?:почему|в\s+ч(?:е|ё)м\s+причина|из-?за\s+чего|откуда\s+разрыв)/iu
]
}
];
function countRuleHits(text, rule) {
let hits = 0;
for (const pattern of rule.patterns) {
if (pattern.test(text)) {
hits += 1;
}
}
return hits;
}
function resolveQuestionType(input) {
const text = String(input ?? "").trim();
if (!text) {
return "unknown";
}
let bestType = "unknown";
let bestHits = 0;
let bestPriority = Number.POSITIVE_INFINITY;
for (const rule of QUESTION_TYPE_RULES) {
if (rule.pattern.test(text)) {
return rule.type;
const hits = countRuleHits(text, rule);
if (hits <= 0) {
continue;
}
if (hits > bestHits || (hits === bestHits && rule.priority < bestPriority)) {
bestType = rule.type;
bestHits = hits;
bestPriority = rule.priority;
}
}
if (/[??]/u.test(text)) {
if (bestType !== "unknown") {
return bestType;
}
if (/[?пјџ]/u.test(text)) {
return "why_breaks";
}
return "unknown";