Закрепить расширенный AGENT-прогон качества 1С-ассистента

This commit is contained in:
dctouch 2026-05-23 09:07:24 +03:00
parent 50d938b8f1
commit e38223e33e
10 changed files with 647 additions and 50 deletions

View File

@ -0,0 +1,189 @@
{
"schema_version": "domain_truth_harness_spec_v1",
"scenario_id": "agent_autonomy_business_quality_20260523",
"domain": "autonomy_business_quality",
"title": "AGENT | Autonomy business quality pack",
"description": "Expanded targeted AGENT replay for the current autonomy milestone: value-flow hot handoff must survive realistic business questions, while final answers must read like a useful 1C analyst instead of runtime/debug prose.",
"bindings": {},
"steps": [
{
"step_id": "step_01_incoming_total_no_counterparties",
"title": "Incoming money total by organization without counterparty split",
"question": "Сколько входящих денег за 2020 год по ООО Альтернатива Плюс без разреза по контрагентам?",
"allowed_reply_types": ["partial_coverage", "factual_with_explanation", "factual"],
"expected_mcp_discovery_response_applied": true,
"expected_mcp_discovery_selected_chain_id": "value_flow",
"expected_mcp_discovery_response_candidate_status": "ready_for_guarded_use",
"expected_mcp_discovery_candidate_hot_runtime_wired": true,
"expected_mcp_discovery_hot_runtime_wired": true,
"expected_mcp_discovery_execution_handoff_status": "ready_for_guarded_response",
"expected_mcp_discovery_execution_handoff_can_use_guarded_response": true,
"expected_catalog_alignment_status": "selected_matches_top",
"expected_catalog_chain_top_match": "value_flow",
"expected_catalog_selected_matches_top": true,
"required_answer_patterns_all": ["2020", "47[\\s.]*628[\\s.]*853", "входящ|поступ|получ", "руб"],
"forbidden_answer_patterns": ["Учтено строк", "Первая найденная дата", "последняя:", "runtime_", "planner_", "query_movements", "primitive", "уточните контрагента", "по какому контрагенту"],
"criticality": "critical",
"semantic_tags": ["autonomy_core", "value_flow", "incoming_total", "business_answer_quality"]
},
{
"step_id": "step_02_outgoing_total_no_counterparties",
"title": "Outgoing money total by organization without counterparty split",
"question": "Сколько исходящих денег за 2020 год по ООО Альтернатива Плюс без разреза по контрагентам?",
"allowed_reply_types": ["partial_coverage", "factual_with_explanation", "factual"],
"expected_mcp_discovery_response_applied": true,
"expected_mcp_discovery_selected_chain_id": "value_flow",
"expected_mcp_discovery_response_candidate_status": "ready_for_guarded_use",
"expected_mcp_discovery_candidate_hot_runtime_wired": true,
"expected_mcp_discovery_hot_runtime_wired": true,
"expected_mcp_discovery_execution_handoff_status": "ready_for_guarded_response",
"expected_mcp_discovery_execution_handoff_can_use_guarded_response": true,
"expected_catalog_alignment_status": "selected_matches_top",
"expected_catalog_chain_top_match": "value_flow",
"expected_catalog_selected_matches_top": true,
"required_answer_patterns_all": ["2020", "исходящ|списан|заплат", "руб"],
"required_answer_patterns_any": ["43[\\s.]*763[\\s.]*351", "не полностью покрыт|лимит|нужно дозапрос"],
"forbidden_answer_patterns": ["Учтено строк", "Первая найденная дата", "последняя:", "runtime_", "planner_", "query_movements", "primitive", "уточните контрагента", "по какому контрагенту"],
"criticality": "critical",
"semantic_tags": ["autonomy_core", "value_flow", "outgoing_total", "business_answer_quality", "limit_honesty"]
},
{
"step_id": "step_03_colloquial_incoming_without_tops",
"title": "Colloquial no-top incoming wording stays value-flow total",
"question": "А всего сколько денег пришло в ООО Альтернатива Плюс за 2020, без топов и без контрагентов?",
"allowed_reply_types": ["partial_coverage", "factual_with_explanation", "factual"],
"expected_mcp_discovery_response_applied": true,
"expected_mcp_discovery_selected_chain_id": "value_flow",
"expected_mcp_discovery_response_candidate_status": "ready_for_guarded_use",
"expected_mcp_discovery_candidate_hot_runtime_wired": true,
"expected_mcp_discovery_hot_runtime_wired": true,
"expected_mcp_discovery_execution_handoff_status": "ready_for_guarded_response",
"expected_mcp_discovery_execution_handoff_can_use_guarded_response": true,
"expected_catalog_alignment_status": "selected_matches_top",
"expected_catalog_chain_top_match": "value_flow",
"expected_catalog_selected_matches_top": true,
"required_answer_patterns_all": ["2020", "47[\\s.]*628[\\s.]*853", "пришл|получ|поступ", "руб"],
"forbidden_answer_patterns": ["топ входящ", "топ контрагент", "Учтено строк", "Первая найденная дата", "runtime_", "planner_", "query_movements", "primitive"],
"criticality": "critical",
"semantic_tags": ["autonomy_core", "value_flow", "no_top_guard", "colloquial_total"]
},
{
"step_id": "step_04_cashflow_overview_2020",
"title": "Adult 2020 money overview with bank separated",
"question": "Теперь дай взрослый обзор за 2020 по компании: входящие, исходящие, нетто, топы, но банк в топах отдельно объясни как финансовый поток.",
"allowed_reply_types": ["partial_coverage", "factual_with_explanation", "factual"],
"expected_catalog_alignment_status": "selected_matches_top",
"expected_catalog_chain_top_match": "business_overview",
"expected_catalog_selected_matches_top": true,
"required_answer_patterns_all": ["47[\\s.]*628[\\s.]*853", "43[\\s.]*763[\\s.]*351", "3[\\s.]*865[\\s.]*501", "Сбербанк|СБЕРБАНК", "финансов|банк", "Группа СВК", "Департамент"],
"required_answer_patterns_any": ["Что проверить дальше", "следующ"],
"forbidden_answer_patterns": ["Учтено строк", "Первая найденная дата", "surrogate", "VAT-объект", "runtime_", "planner_", "query_movements", "primitive"],
"criticality": "critical",
"semantic_tags": ["business_overview", "cashflow_overview", "bank_boundary", "next_action"]
},
{
"step_id": "step_05_money_earned_vs_profit",
"title": "Colloquial earned money is cashflow, not clean profit",
"question": "скока денег альтернатива заработала за 20 год?",
"allowed_reply_types": ["partial_coverage", "factual_with_explanation", "factual"],
"required_answer_patterns_all": ["47[\\s.]*628[\\s.]*853", "43[\\s.]*763[\\s.]*351", "3[\\s.]*865[\\s.]*501", "не чистая прибыль|не прибыль|денежн"],
"forbidden_answer_patterns": ["Учтено строк", "Первая найденная дата", "surrogate", "runtime_", "planner_", "query_movements", "primitive"],
"criticality": "critical",
"semantic_tags": ["cashflow_vs_profit", "colloquial_money"]
},
{
"step_id": "step_06_profit_followup",
"title": "Follow-up clean profit keeps cashflow/profit distinction",
"question": "а это чистая прибыль?",
"allowed_reply_types": ["partial_coverage", "factual_with_explanation", "factual"],
"required_answer_patterns_all": ["нет|не", "чистая прибыль|прибыль", "7\\s*136\\s*815|7,?136,?815|7136815", "90|91|99"],
"forbidden_answer_patterns": ["Учтено строк", "Первая найденная дата", "runtime_", "planner_", "query_movements", "primitive"],
"criticality": "critical",
"semantic_tags": ["followup_context", "profit_vs_cashflow"]
},
{
"step_id": "step_07_sberbank_financial_flow",
"title": "Sberbank role is financial flow, not ordinary customer/supplier",
"question": "А отдельно по СБЕРБАНКУ: он для нас клиент, поставщик или финансовый поток? Дай коротко по подтвержденным строкам.",
"allowed_reply_types": ["partial_coverage", "factual_with_explanation", "factual"],
"required_answer_patterns_all": ["Сбербанк|СБЕРБАНК", "финансов|банк", "не.*клиент|не.*поставщик|не обычн", "36[\\s.]*258[\\s.]*835|12[\\s.]*792[\\s.]*194"],
"forbidden_answer_patterns": ["0 / 0", "T00:00:00", "Учтено строк", "Первая найденная дата", "Примеры строк", "Показаны первые", "runtime_", "planner_", "query_movements", "primitive"],
"criticality": "critical",
"semantic_tags": ["bank_classification", "business_answer_quality"]
},
{
"step_id": "step_08_svk_counterparty_net_flow",
"title": "Counterparty net-flow does not become company profit",
"question": "какое нетто по деньгам с Группа СВК за 2020 год: сколько получили и сколько заплатили?",
"allowed_reply_types": ["partial_coverage", "factual_with_explanation", "factual"],
"required_answer_patterns_all": ["Группа СВК", "12[\\s.]*093[\\s.]*465", "заплатили|исходящ", "0", "нетто"],
"forbidden_answer_patterns": ["чистая прибыль", "90/91/99", "7[\\s.]*136[\\s.]*815", "Учтено строк", "Первая найденная дата", "Примеры строк", "Показаны первые", "runtime_", "planner_", "query_movements", "primitive"],
"criticality": "critical",
"semantic_tags": ["counterparty_value_flow", "net_flow", "no_profit_substitution"]
},
{
"step_id": "step_09_payables_end_2020",
"title": "Payables answer stays compact and business-first",
"question": "кому мы должны на конец 2020?",
"allowed_reply_types": ["partial_coverage", "factual_with_explanation", "factual"],
"required_answer_patterns_all": ["1[\\s.]*713[\\s.]*210", "ИП Тучкова|Тучкова", "должн|кредитор"],
"forbidden_answer_patterns": ["T23:59:59", "эвристический", "shortlist", "Строк в выборке", "Учтено строк", "runtime_", "planner_", "query_movements", "primitive"],
"criticality": "critical",
"semantic_tags": ["payables", "debt_answer_quality"]
},
{
"step_id": "step_10_receivables_end_2020",
"title": "Receivables answer stays compact and business-first",
"question": "а нам кто должен на конец 2020?",
"allowed_reply_types": ["partial_coverage", "factual_with_explanation", "factual"],
"required_answer_patterns_all": ["1[\\s.]*219[\\s.]*200", "СервисКонсалт", "должн|дебитор"],
"forbidden_answer_patterns": ["T23:59:59", "эвристический", "shortlist", "Строк в выборке", "Категории дебиторской задолженности", "Учтено строк", "runtime_", "planner_", "query_movements", "primitive"],
"criticality": "critical",
"semantic_tags": ["receivables", "debt_answer_quality"]
},
{
"step_id": "step_11_vat_december_2019",
"title": "VAT answer is clean user-facing accounting answer",
"question": "сколько НДС надо заплатить в налоговую за декабрь 2019?",
"allowed_reply_types": ["partial_coverage", "factual_with_explanation", "factual"],
"required_answer_patterns_all": ["161[\\s.]*852", "к уплате", "книга продаж|продаж", "книга покупок|вычет|покупок", "01\\.10\\.2019|4 квартал|IV квартал"],
"forbidden_answer_patterns": ["surrogate", "VAT-объект", "прямых источников", "0,00\\s*₽", "Учтено строк", "runtime_", "planner_", "query_movements", "primitive"],
"criticality": "critical",
"semantic_tags": ["vat", "technical_garbage_guard"]
},
{
"step_id": "step_12_business_evaluation",
"title": "Company evaluation is an analyst answer with next checks",
"question": "Как ты оценишь деятельность компании?",
"allowed_reply_types": ["partial_coverage", "factual_with_explanation", "factual"],
"expected_catalog_alignment_status": "selected_matches_top",
"expected_catalog_chain_top_match": "business_overview",
"expected_catalog_selected_matches_top": true,
"required_answer_patterns_all": ["крупн|контракт|проект", "285\\s*8|285\\s*823|285", "Комитет|госуслуг", "Что проверить дальше|проверить дальше|дальше"],
"forbidden_answer_patterns": ["Учтено строк", "Первая найденная дата", "проверка достигла лимита строк", "runtime_", "planner_", "query_movements", "primitive"],
"criticality": "critical",
"semantic_tags": ["business_overview", "business_evaluation", "next_action"]
},
{
"step_id": "step_13_nomenclature_margin_missing_period",
"title": "Nomenclature margin ranking asks for period, not wrong accounting domain",
"question": "Какая номенклатура товара реализована с высокой прибылью какая с низкой?",
"allowed_reply_types": ["partial_coverage", "factual_with_explanation", "factual"],
"required_answer_patterns_all": ["период", "выручк|реализац", "себестоим|валов|маржин"],
"forbidden_answer_patterns": ["основн.*средств", "амортизац", "зависш", "оплат", "расчетн", "Учтено строк", "runtime_", "planner_", "query_movements", "primitive"],
"criticality": "critical",
"semantic_tags": ["nomenclature_margin", "clarification", "domain_purity"]
},
{
"step_id": "step_14_nomenclature_margin_may_2020",
"title": "Nomenclature margin ranking with period gives useful limited answer",
"question": "май 2020",
"allowed_reply_types": ["partial_coverage", "factual_with_explanation", "factual"],
"required_answer_patterns_all": ["май|01\\.05\\.2020|31\\.05\\.2020", "рейтинг|прибыль|маржин", "себестоим", "нельзя|не удалось|недостаточно"],
"required_answer_patterns_any": ["показать найденную продажу", "расширить период", "90\\.01|90\\.02", "следующ"],
"forbidden_answer_patterns": ["основн.*средств", "амортизац", "зависш", "runtime_", "planner_", "query_movements", "primitive"],
"criticality": "critical",
"semantic_tags": ["nomenclature_margin", "limited_answer", "next_action"]
}
]
}

View File

@ -382,7 +382,7 @@ function classifyBankOperationSemanticBucket(row) {
} }
function bankOperationSemanticBucketLabel(bucket) { function bankOperationSemanticBucketLabel(bucket) {
if (bucket === "commission") { if (bucket === "commission") {
return "комиссии и банковое обслуживание"; return "комиссии и банковское обслуживание";
} }
if (bucket === "deposit_or_credit") { if (bucket === "deposit_or_credit") {
return "депозиты, кредиты или проценты"; return "депозиты, кредиты или проценты";
@ -3886,6 +3886,7 @@ function composeFactualReplyBody(intent, rows, options = {}) {
(String(right.period ?? "").localeCompare(String(left.period ?? ""), "ru"))) (String(right.period ?? "").localeCompare(String(left.period ?? ""), "ru")))
.slice(0, Math.min(rows.length, 5)); .slice(0, Math.min(rows.length, 5));
const semanticSummary = summarizeBankOperationSemantics(rows); const semanticSummary = summarizeBankOperationSemantics(rows);
const compactRoleAnswer = /(?:клиент|поставщик|финансов|роль|коротко)/iu.test(String(options.userMessage ?? ""));
const compactEvidenceRows = visibleRows.map((row, index) => { const compactEvidenceRows = visibleRows.map((row, index) => {
const direction = bankOperationDirectionLabel(bankOperationDirection(row)); const direction = bankOperationDirectionLabel(bankOperationDirection(row));
const amount = formatMoneyRub(row.amount ?? 0); const amount = formatMoneyRub(row.amount ?? 0);
@ -3901,13 +3902,13 @@ function composeFactualReplyBody(intent, rows, options = {}) {
`Коротко: найдено банковских операций${counterparty ? ` по ${counterparty}` : " по контрагенту"}${rows.length}.`, `Коротко: найдено банковских операций${counterparty ? ` по ${counterparty}` : " по контрагенту"}${rows.length}.`,
summarizeBankOperationDirections(rows), summarizeBankOperationDirections(rows),
roleBoundary ?? "Показываю подтвержденные банковские операции из текущего среза.", roleBoundary ?? "Показываю подтвержденные банковские операции из текущего среза.",
bankOperationEvidenceLine(rows, preferredBankEvidenceDirection(options.userMessage)), ...(semanticSummary ? [semanticSummary] : [])
...(semanticSummary ? [semanticSummary] : []),
"Примеры строк 1С:",
...compactEvidenceRows,
"Следующий шаг: могу отдельно разложить назначения платежа, договоры или отделить банковский контур от клиентского/поставщицкого."
]; ];
if (rows.length > visibleRows.length) { if (!compactRoleAnswer) {
lines.push(bankOperationEvidenceLine(rows, preferredBankEvidenceDirection(options.userMessage)), "Примеры строк 1С:", ...compactEvidenceRows);
}
lines.push("Следующий шаг: могу отдельно разложить назначения платежа, договоры или отделить банковский контур от клиентского/поставщицкого.");
if (!compactRoleAnswer && rows.length > visibleRows.length) {
lines.push(`Показаны первые ${visibleRows.length} из ${rows.length}; полный список остается в подтвержденном срезе.`); lines.push(`Показаны первые ${visibleRows.length} из ${rows.length}; полный список остается в подтвержденном срезе.`);
} }
return { return {

View File

@ -1212,22 +1212,16 @@ function derivedValueFlowConfirmedLine(pilot) {
const organization = organizationScope ? ` по организации ${organizationScope}` : ""; const organization = organizationScope ? ` по организации ${organizationScope}` : "";
const counterparty = flow.counterparty ? ` по контрагенту ${flow.counterparty}` : ""; const counterparty = flow.counterparty ? ` по контрагенту ${flow.counterparty}` : "";
const period = flow.period_scope ? ` за период ${flow.period_scope}` : " в проверенном окне"; const period = flow.period_scope ? ` за период ${flow.period_scope}` : " в проверенном окне";
const movementLabel = flow.value_flow_direction === "outgoing_supplier_payout"
? "исходящих платежей/списаний"
: "входящих денежных поступлений";
const totalLabel = flow.value_flow_direction === "outgoing_supplier_payout" const totalLabel = flow.value_flow_direction === "outgoing_supplier_payout"
? "сумма исходящих платежей/списаний составляет" ? "исходящие платежи/списания"
: "сумма входящих денежных поступлений составляет"; : "входящие денежные поступления";
const caveat = flow.value_flow_direction === "outgoing_supplier_payout" const caveat = flow.value_flow_direction === "outgoing_supplier_payout"
? "Это расчет по найденным строкам 1С, а не подтверждение полного объема платежей вне проверенного окна." ? "Граница: это проверенный денежный срез по найденным списаниям в 1С, не внешний аудит всех платежей вне этого окна."
: "Это расчет по найденным строкам 1С, а не подтверждение полного объема поступлений вне проверенного окна."; : "Граница: это проверенный денежный срез по найденным поступлениям в 1С, не внешний аудит всех поступлений вне этого окна.";
const dates = flow.first_movement_date && flow.latest_movement_date
? ` Первая найденная дата движения: ${flow.first_movement_date}; последняя: ${flow.latest_movement_date}.`
: "";
const limitCaveat = flow.coverage_limited_by_probe_limit const limitCaveat = flow.coverage_limited_by_probe_limit
? " Лимит строк проверки достигнут; полный запрошенный период может быть покрыт не полностью." ? " Проверка уперлась в лимит строк, поэтому полный период может быть покрыт не полностью."
: ""; : "";
return `По найденным строкам ${movementLabel} в 1С${counterparty}${period} ${totalLabel} ${flow.total_amount_human_ru} Учтено строк с суммой: ${flow.rows_with_amount} из ${flow.rows_matched}.${dates}${limitCaveat} ${caveat}`; return `${totalLabel}${counterparty || organization}${period}: ${flow.total_amount_human_ru}.${limitCaveat} ${caveat}`;
} }
function derivedValueFlowMonthlyLines(pilot) { function derivedValueFlowMonthlyLines(pilot) {
const flow = pilot.derived_value_flow; const flow = pilot.derived_value_flow;
@ -1831,7 +1825,7 @@ function buildAssistantMcpDiscoveryAnswerDraft(pilot) {
: pilot.derived_ranked_value_flow && derivedValueLine : pilot.derived_ranked_value_flow && derivedValueLine
? [derivedValueLine] ? [derivedValueLine]
: derivedValueLine : derivedValueLine
? [...pilot.evidence.confirmed_facts, derivedValueLine, ...monthlyConfirmedLines] ? [derivedValueLine, ...monthlyConfirmedLines]
: valueFlowZeroResultConfirmedLine(pilot) : valueFlowZeroResultConfirmedLine(pilot)
? [valueFlowZeroResultConfirmedLine(pilot)] ? [valueFlowZeroResultConfirmedLine(pilot)]
: derivedEntityResolutionLine : derivedEntityResolutionLine

View File

@ -520,14 +520,12 @@ function businessOverviewInventoryLine(overview) {
} }
const amount = moneyText(inventory.total_amount_human_ru); const amount = moneyText(inventory.total_amount_human_ru);
const rows = Number(inventory.rows_matched); const rows = Number(inventory.rows_matched);
const quantity = Number(inventory.total_quantity);
if (!amount && !Number.isFinite(rows)) { if (!amount && !Number.isFinite(rows)) {
return null; return null;
} }
const pieces = [ const pieces = [
Number.isFinite(rows) ? `${rows} позиций` : null, Number.isFinite(rows) ? `${rows} позиций` : null,
amount ? `на ${sentenceAmount(amount) ?? amount}` : null, amount ? `на ${sentenceAmount(amount) ?? amount}` : null
Number.isFinite(quantity) && quantity > 0 ? `количество ${quantity}` : null
].filter((item) => Boolean(item)); ].filter((item) => Boolean(item));
return pieces.length > 0 ? `Склад: ${pieces.join(", ")}.` : null; return pieces.length > 0 ? `Склад: ${pieces.join(", ")}.` : null;
} }
@ -919,7 +917,7 @@ function buildCompactBusinessOverviewReply(entryPoint, draft) {
} }
if (customerName && customerAmount) { if (customerName && customerAmount) {
lines.push(topCustomerLooksFinancial lines.push(topCustomerLooksFinancial
? `- крупнейший входящий источник: ${customerName}${sentenceAmount(customerAmount) ?? customerAmount}; это похоже на финансовый контур, не на обычную клиентскую выручку;` ? `- крупнейший входящий источник: ${customerName}${sentenceAmount(customerAmount) ?? customerAmount}; это похоже на финансовый контур, не на обычную клиентскую выручку;${nonFinancialCustomer ? ` крупнейший небанковский входящий контрагент: ${nonFinancialCustomer};` : ""}`
: `- крупнейший источник денег: ${customerName}${sentenceAmount(customerAmount) ?? customerAmount}; это сигнал концентрации на крупном заказчике;`); : `- крупнейший источник денег: ${customerName}${sentenceAmount(customerAmount) ?? customerAmount}; это сигнал концентрации на крупном заказчике;`);
} }
if (topSupplier) { if (topSupplier) {

View File

@ -549,7 +549,7 @@ function classifyBankOperationSemanticBucket(row: ComposeStageRow): BankOperatio
function bankOperationSemanticBucketLabel(bucket: BankOperationSemanticBucket): string { function bankOperationSemanticBucketLabel(bucket: BankOperationSemanticBucket): string {
if (bucket === "commission") { if (bucket === "commission") {
return "комиссии и банковое обслуживание"; return "комиссии и банковское обслуживание";
} }
if (bucket === "deposit_or_credit") { if (bucket === "deposit_or_credit") {
return "депозиты, кредиты или проценты"; return "депозиты, кредиты или проценты";
@ -4940,6 +4940,7 @@ function composeFactualReplyBody(
) )
.slice(0, Math.min(rows.length, 5)); .slice(0, Math.min(rows.length, 5));
const semanticSummary = summarizeBankOperationSemantics(rows); const semanticSummary = summarizeBankOperationSemantics(rows);
const compactRoleAnswer = /(?:клиент|поставщик|финансов|роль|коротко)/iu.test(String(options.userMessage ?? ""));
const compactEvidenceRows = visibleRows.map((row, index) => { const compactEvidenceRows = visibleRows.map((row, index) => {
const direction = bankOperationDirectionLabel(bankOperationDirection(row)); const direction = bankOperationDirectionLabel(bankOperationDirection(row));
const amount = formatMoneyRub(row.amount ?? 0); const amount = formatMoneyRub(row.amount ?? 0);
@ -4955,13 +4956,17 @@ function composeFactualReplyBody(
`Коротко: найдено банковских операций${counterparty ? ` по ${counterparty}` : " по контрагенту"}${rows.length}.`, `Коротко: найдено банковских операций${counterparty ? ` по ${counterparty}` : " по контрагенту"}${rows.length}.`,
summarizeBankOperationDirections(rows), summarizeBankOperationDirections(rows),
roleBoundary ?? "Показываю подтвержденные банковские операции из текущего среза.", roleBoundary ?? "Показываю подтвержденные банковские операции из текущего среза.",
bankOperationEvidenceLine(rows, preferredBankEvidenceDirection(options.userMessage)), ...(semanticSummary ? [semanticSummary] : [])
...(semanticSummary ? [semanticSummary] : []),
"Примеры строк 1С:",
...compactEvidenceRows,
"Следующий шаг: могу отдельно разложить назначения платежа, договоры или отделить банковский контур от клиентского/поставщицкого."
]; ];
if (rows.length > visibleRows.length) { if (!compactRoleAnswer) {
lines.push(
bankOperationEvidenceLine(rows, preferredBankEvidenceDirection(options.userMessage)),
"Примеры строк 1С:",
...compactEvidenceRows
);
}
lines.push("Следующий шаг: могу отдельно разложить назначения платежа, договоры или отделить банковский контур от клиентского/поставщицкого.");
if (!compactRoleAnswer && rows.length > visibleRows.length) {
lines.push(`Показаны первые ${visibleRows.length} из ${rows.length}; полный список остается в подтвержденном срезе.`); lines.push(`Показаны первые ${visibleRows.length} из ${rows.length}; полный список остается в подтвержденном срезе.`);
} }
return { return {

View File

@ -1392,26 +1392,18 @@ function derivedValueFlowConfirmedLine(pilot: AssistantMcpDiscoveryPilotExecutio
const organization = organizationScope ? ` по организации ${organizationScope}` : ""; const organization = organizationScope ? ` по организации ${organizationScope}` : "";
const counterparty = flow.counterparty ? ` по контрагенту ${flow.counterparty}` : ""; const counterparty = flow.counterparty ? ` по контрагенту ${flow.counterparty}` : "";
const period = flow.period_scope ? ` за период ${flow.period_scope}` : " в проверенном окне"; const period = flow.period_scope ? ` за период ${flow.period_scope}` : " в проверенном окне";
const movementLabel =
flow.value_flow_direction === "outgoing_supplier_payout"
? "исходящих платежей/списаний"
: "входящих денежных поступлений";
const totalLabel = const totalLabel =
flow.value_flow_direction === "outgoing_supplier_payout" flow.value_flow_direction === "outgoing_supplier_payout"
? "сумма исходящих платежей/списаний составляет" ? "исходящие платежи/списания"
: "сумма входящих денежных поступлений составляет"; : "входящие денежные поступления";
const caveat = const caveat =
flow.value_flow_direction === "outgoing_supplier_payout" flow.value_flow_direction === "outgoing_supplier_payout"
? "Это расчет по найденным строкам 1С, а не подтверждение полного объема платежей вне проверенного окна." ? "Граница: это проверенный денежный срез по найденным списаниям в 1С, не внешний аудит всех платежей вне этого окна."
: "Это расчет по найденным строкам 1С, а не подтверждение полного объема поступлений вне проверенного окна."; : "Граница: это проверенный денежный срез по найденным поступлениям в 1С, не внешний аудит всех поступлений вне этого окна.";
const dates =
flow.first_movement_date && flow.latest_movement_date
? ` Первая найденная дата движения: ${flow.first_movement_date}; последняя: ${flow.latest_movement_date}.`
: "";
const limitCaveat = flow.coverage_limited_by_probe_limit const limitCaveat = flow.coverage_limited_by_probe_limit
? " Лимит строк проверки достигнут; полный запрошенный период может быть покрыт не полностью." ? " Проверка уперлась в лимит строк, поэтому полный период может быть покрыт не полностью."
: ""; : "";
return `По найденным строкам ${movementLabel} в 1С${counterparty}${period} ${totalLabel} ${flow.total_amount_human_ru} Учтено строк с суммой: ${flow.rows_with_amount} из ${flow.rows_matched}.${dates}${limitCaveat} ${caveat}`; return `${totalLabel}${counterparty || organization}${period}: ${flow.total_amount_human_ru}.${limitCaveat} ${caveat}`;
} }
function derivedValueFlowMonthlyLines(pilot: AssistantMcpDiscoveryPilotExecutionContract): string[] { function derivedValueFlowMonthlyLines(pilot: AssistantMcpDiscoveryPilotExecutionContract): string[] {
@ -2109,7 +2101,7 @@ export function buildAssistantMcpDiscoveryAnswerDraft(
: pilot.derived_ranked_value_flow && derivedValueLine : pilot.derived_ranked_value_flow && derivedValueLine
? [derivedValueLine] ? [derivedValueLine]
: derivedValueLine : derivedValueLine
? [...pilot.evidence.confirmed_facts, derivedValueLine, ...monthlyConfirmedLines] ? [derivedValueLine, ...monthlyConfirmedLines]
: valueFlowZeroResultConfirmedLine(pilot) : valueFlowZeroResultConfirmedLine(pilot)
? [valueFlowZeroResultConfirmedLine(pilot)!] ? [valueFlowZeroResultConfirmedLine(pilot)!]
: derivedEntityResolutionLine : derivedEntityResolutionLine

View File

@ -602,14 +602,12 @@ function businessOverviewInventoryLine(overview: Record<string, unknown>): strin
} }
const amount = moneyText(inventory.total_amount_human_ru); const amount = moneyText(inventory.total_amount_human_ru);
const rows = Number(inventory.rows_matched); const rows = Number(inventory.rows_matched);
const quantity = Number(inventory.total_quantity);
if (!amount && !Number.isFinite(rows)) { if (!amount && !Number.isFinite(rows)) {
return null; return null;
} }
const pieces = [ const pieces = [
Number.isFinite(rows) ? `${rows} позиций` : null, Number.isFinite(rows) ? `${rows} позиций` : null,
amount ? `на ${sentenceAmount(amount) ?? amount}` : null, amount ? `на ${sentenceAmount(amount) ?? amount}` : null
Number.isFinite(quantity) && quantity > 0 ? `количество ${quantity}` : null
].filter((item): item is string => Boolean(item)); ].filter((item): item is string => Boolean(item));
return pieces.length > 0 ? `Склад: ${pieces.join(", ")}.` : null; return pieces.length > 0 ? `Склад: ${pieces.join(", ")}.` : null;
} }
@ -1098,7 +1096,7 @@ function buildCompactBusinessOverviewReply(
if (customerName && customerAmount) { if (customerName && customerAmount) {
lines.push( lines.push(
topCustomerLooksFinancial topCustomerLooksFinancial
? `- крупнейший входящий источник: ${customerName}${sentenceAmount(customerAmount) ?? customerAmount}; это похоже на финансовый контур, не на обычную клиентскую выручку;` ? `- крупнейший входящий источник: ${customerName}${sentenceAmount(customerAmount) ?? customerAmount}; это похоже на финансовый контур, не на обычную клиентскую выручку;${nonFinancialCustomer ? ` крупнейший небанковский входящий контрагент: ${nonFinancialCustomer};` : ""}`
: `- крупнейший источник денег: ${customerName}${sentenceAmount(customerAmount) ?? customerAmount}; это сигнал концентрации на крупном заказчике;` : `- крупнейший источник денег: ${customerName}${sentenceAmount(customerAmount) ?? customerAmount}; это сигнал концентрации на крупном заказчике;`
); );
} }

View File

@ -1,4 +1,82 @@
[ [
{
"generation_id": "gen-ag05230604-098bda",
"created_at": "2026-05-23T06:04:40+00:00",
"mode": "saved_user_sessions",
"title": "AGENT | Autonomy business quality pack",
"count": 14,
"domain": "autonomy_business_quality",
"questions": [
"Сколько входящих денег за 2020 год по ООО Альтернатива Плюс без разреза по контрагентам?",
"Сколько исходящих денег за 2020 год по ООО Альтернатива Плюс без разреза по контрагентам?",
"А всего сколько денег пришло в ООО Альтернатива Плюс за 2020, без топов и без контрагентов?",
"Теперь дай взрослый обзор за 2020 по компании: входящие, исходящие, нетто, топы, но банк в топах отдельно объясни как финансовый поток.",
"скока денег альтернатива заработала за 20 год?",
"а это чистая прибыль?",
"А отдельно по СБЕРБАНКУ: он для нас клиент, поставщик или финансовый поток? Дай коротко по подтвержденным строкам.",
"какое нетто по деньгам с Группа СВК за 2020 год: сколько получили и сколько заплатили?",
"кому мы должны на конец 2020?",
"а нам кто должен на конец 2020?",
"сколько НДС надо заплатить в налоговую за декабрь 2019?",
"Как ты оценишь деятельность компании?",
"Какая номенклатура товара реализована с высокой прибылью какая с низкой?",
"май 2020"
],
"generated_by": "codex_agent",
"saved_case_set_file": "assistant_autogen_saved_user_sessions_20260523060440_gen-ag05230604-098bda.json",
"context": {
"llm_provider": null,
"model": null,
"assistant_prompt_version": null,
"decomposition_prompt_version": null,
"prompt_fingerprint": null,
"autogen_personality_id": null,
"autogen_personality_prompt": null,
"source_session_id": null,
"saved_session_file": "assistant_saved_session_20260523060440_gen-ag05230604-098bda.json",
"saved_case_set_kind": "agent_semantic_scenario",
"agent_run": true,
"agent_focus": "Expanded targeted AGENT replay for the current autonomy milestone: value-flow hot handoff must survive realistic business questions, while final answers must read like a useful 1C analyst instead of runtime/debug prose.",
"architecture_phase": "turnaround_11",
"source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\agent_autonomy_business_quality_20260523.json",
"scenario_id": "agent_autonomy_business_quality_20260523",
"semantic_tags": [
"autonomy_core",
"bank_boundary",
"bank_classification",
"business_answer_quality",
"business_evaluation",
"business_overview",
"cashflow_overview",
"cashflow_vs_profit",
"clarification",
"colloquial_money",
"colloquial_total",
"counterparty_value_flow",
"debt_answer_quality",
"domain_purity",
"followup_context",
"incoming_total",
"limit_honesty",
"limited_answer",
"net_flow",
"next_action",
"no_profit_substitution",
"no_top_guard",
"nomenclature_margin",
"outgoing_total",
"payables",
"profit_vs_cashflow",
"receivables",
"technical_garbage_guard",
"value_flow",
"vat"
],
"validation_status": "accepted_live_replay",
"validated_run_dir": "artifacts\\domain_runs\\agent_autonomy_business_quality_live4",
"saved_after_validated_replay": true
}
},
{ {
"generation_id": "gen-ag05221957-713bbd", "generation_id": "gen-ag05221957-713bbd",
"created_at": "2026-05-22T19:57:37+00:00", "created_at": "2026-05-22T19:57:37+00:00",

View File

@ -0,0 +1,275 @@
{
"saved_at": "2026-05-23T06:04:40+00:00",
"generation_id": "gen-ag05230604-098bda",
"mode": "saved_user_sessions",
"title": "AGENT | Autonomy business quality pack",
"agent_run": true,
"questions": [
"Сколько входящих денег за 2020 год по ООО Альтернатива Плюс без разреза по контрагентам?",
"Сколько исходящих денег за 2020 год по ООО Альтернатива Плюс без разреза по контрагентам?",
"А всего сколько денег пришло в ООО Альтернатива Плюс за 2020, без топов и без контрагентов?",
"Теперь дай взрослый обзор за 2020 по компании: входящие, исходящие, нетто, топы, но банк в топах отдельно объясни как финансовый поток.",
"скока денег альтернатива заработала за 20 год?",
"а это чистая прибыль?",
"А отдельно по СБЕРБАНКУ: он для нас клиент, поставщик или финансовый поток? Дай коротко по подтвержденным строкам.",
"какое нетто по деньгам с Группа СВК за 2020 год: сколько получили и сколько заплатили?",
"кому мы должны на конец 2020?",
"а нам кто должен на конец 2020?",
"сколько НДС надо заплатить в налоговую за декабрь 2019?",
"Как ты оценишь деятельность компании?",
"Какая номенклатура товара реализована с высокой прибылью какая с низкой?",
"май 2020"
],
"metadata": {
"assistant_prompt_version": null,
"decomposition_prompt_version": null,
"prompt_fingerprint": null,
"agent_focus": "Expanded targeted AGENT replay for the current autonomy milestone: value-flow hot handoff must survive realistic business questions, while final answers must read like a useful 1C analyst instead of runtime/debug prose.",
"architecture_phase": "turnaround_11",
"source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\agent_autonomy_business_quality_20260523.json",
"scenario_id": "agent_autonomy_business_quality_20260523",
"semantic_tags": [
"autonomy_core",
"bank_boundary",
"bank_classification",
"business_answer_quality",
"business_evaluation",
"business_overview",
"cashflow_overview",
"cashflow_vs_profit",
"clarification",
"colloquial_money",
"colloquial_total",
"counterparty_value_flow",
"debt_answer_quality",
"domain_purity",
"followup_context",
"incoming_total",
"limit_honesty",
"limited_answer",
"net_flow",
"next_action",
"no_profit_substitution",
"no_top_guard",
"nomenclature_margin",
"outgoing_total",
"payables",
"profit_vs_cashflow",
"receivables",
"technical_garbage_guard",
"value_flow",
"vat"
],
"validation_status": "accepted_live_replay",
"validated_run_dir": "artifacts\\domain_runs\\agent_autonomy_business_quality_live4",
"saved_after_validated_replay": true,
"save_gate": {
"schema_version": "agent_semantic_save_gate_v1",
"validation_status": "accepted_live_replay",
"validated_run_dir": "artifacts\\domain_runs\\agent_autonomy_business_quality_live4",
"final_status": "accepted",
"review_overall_status": "pass",
"business_overall_status": "pass",
"steps_total": 14,
"steps_passed": 14,
"steps_failed": 0,
"steps_with_business_failures": 0,
"steps_with_business_warnings": 0,
"acceptance_gate_passed": true,
"saved_after_validated_replay": true
}
},
"source_session_id": null,
"session": {
"session_id": null,
"mode": "agent_semantic_run",
"items": [
{
"message_id": "agent-user-001",
"role": "user",
"text": "Сколько входящих денег за 2020 год по ООО Альтернатива Плюс без разреза по контрагентам?",
"created_at": "2026-05-23T06:04:40+00:00",
"reply_type": null,
"trace_id": null,
"debug": null
},
{
"message_id": "agent-user-002",
"role": "user",
"text": "Сколько исходящих денег за 2020 год по ООО Альтернатива Плюс без разреза по контрагентам?",
"created_at": "2026-05-23T06:04:40+00:00",
"reply_type": null,
"trace_id": null,
"debug": null
},
{
"message_id": "agent-user-003",
"role": "user",
"text": "А всего сколько денег пришло в ООО Альтернатива Плюс за 2020, без топов и без контрагентов?",
"created_at": "2026-05-23T06:04:40+00:00",
"reply_type": null,
"trace_id": null,
"debug": null
},
{
"message_id": "agent-user-004",
"role": "user",
"text": "Теперь дай взрослый обзор за 2020 по компании: входящие, исходящие, нетто, топы, но банк в топах отдельно объясни как финансовый поток.",
"created_at": "2026-05-23T06:04:40+00:00",
"reply_type": null,
"trace_id": null,
"debug": null
},
{
"message_id": "agent-user-005",
"role": "user",
"text": "скока денег альтернатива заработала за 20 год?",
"created_at": "2026-05-23T06:04:40+00:00",
"reply_type": null,
"trace_id": null,
"debug": null
},
{
"message_id": "agent-user-006",
"role": "user",
"text": "а это чистая прибыль?",
"created_at": "2026-05-23T06:04:40+00:00",
"reply_type": null,
"trace_id": null,
"debug": null
},
{
"message_id": "agent-user-007",
"role": "user",
"text": "А отдельно по СБЕРБАНКУ: он для нас клиент, поставщик или финансовый поток? Дай коротко по подтвержденным строкам.",
"created_at": "2026-05-23T06:04:40+00:00",
"reply_type": null,
"trace_id": null,
"debug": null
},
{
"message_id": "agent-user-008",
"role": "user",
"text": "какое нетто по деньгам с Группа СВК за 2020 год: сколько получили и сколько заплатили?",
"created_at": "2026-05-23T06:04:40+00:00",
"reply_type": null,
"trace_id": null,
"debug": null
},
{
"message_id": "agent-user-009",
"role": "user",
"text": "кому мы должны на конец 2020?",
"created_at": "2026-05-23T06:04:40+00:00",
"reply_type": null,
"trace_id": null,
"debug": null
},
{
"message_id": "agent-user-010",
"role": "user",
"text": "а нам кто должен на конец 2020?",
"created_at": "2026-05-23T06:04:40+00:00",
"reply_type": null,
"trace_id": null,
"debug": null
},
{
"message_id": "agent-user-011",
"role": "user",
"text": "сколько НДС надо заплатить в налоговую за декабрь 2019?",
"created_at": "2026-05-23T06:04:40+00:00",
"reply_type": null,
"trace_id": null,
"debug": null
},
{
"message_id": "agent-user-012",
"role": "user",
"text": "Как ты оценишь деятельность компании?",
"created_at": "2026-05-23T06:04:40+00:00",
"reply_type": null,
"trace_id": null,
"debug": null
},
{
"message_id": "agent-user-013",
"role": "user",
"text": "Какая номенклатура товара реализована с высокой прибылью какая с низкой?",
"created_at": "2026-05-23T06:04:40+00:00",
"reply_type": null,
"trace_id": null,
"debug": null
},
{
"message_id": "agent-user-014",
"role": "user",
"text": "май 2020",
"created_at": "2026-05-23T06:04:40+00:00",
"reply_type": null,
"trace_id": null,
"debug": null
}
],
"agent_run": true,
"metadata": {
"assistant_prompt_version": null,
"decomposition_prompt_version": null,
"prompt_fingerprint": null,
"agent_focus": "Expanded targeted AGENT replay for the current autonomy milestone: value-flow hot handoff must survive realistic business questions, while final answers must read like a useful 1C analyst instead of runtime/debug prose.",
"architecture_phase": "turnaround_11",
"source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\agent_autonomy_business_quality_20260523.json",
"scenario_id": "agent_autonomy_business_quality_20260523",
"semantic_tags": [
"autonomy_core",
"bank_boundary",
"bank_classification",
"business_answer_quality",
"business_evaluation",
"business_overview",
"cashflow_overview",
"cashflow_vs_profit",
"clarification",
"colloquial_money",
"colloquial_total",
"counterparty_value_flow",
"debt_answer_quality",
"domain_purity",
"followup_context",
"incoming_total",
"limit_honesty",
"limited_answer",
"net_flow",
"next_action",
"no_profit_substitution",
"no_top_guard",
"nomenclature_margin",
"outgoing_total",
"payables",
"profit_vs_cashflow",
"receivables",
"technical_garbage_guard",
"value_flow",
"vat"
],
"validation_status": "accepted_live_replay",
"validated_run_dir": "artifacts\\domain_runs\\agent_autonomy_business_quality_live4",
"saved_after_validated_replay": true,
"save_gate": {
"schema_version": "agent_semantic_save_gate_v1",
"validation_status": "accepted_live_replay",
"validated_run_dir": "artifacts\\domain_runs\\agent_autonomy_business_quality_live4",
"final_status": "accepted",
"review_overall_status": "pass",
"business_overall_status": "pass",
"steps_total": 14,
"steps_passed": 14,
"steps_failed": 0,
"steps_with_business_failures": 0,
"steps_with_business_warnings": 0,
"acceptance_gate_passed": true,
"saved_after_validated_replay": true
}
}
}
}

View File

@ -0,0 +1,67 @@
{
"suite_id": "assistant_saved_session_gen-ag05230604-098bda",
"suite_version": "0.1.0",
"schema_version": "assistant_saved_session_suite_v0_1",
"generated_at": "2026-05-23T06:04:40+00:00",
"generation_id": "gen-ag05230604-098bda",
"mode": "saved_user_sessions",
"title": "AGENT | Autonomy business quality pack",
"domain": "autonomy_business_quality",
"scenario_count": 1,
"case_ids": [
"SAVED-001"
],
"cases": [
{
"case_id": "SAVED-001",
"scenario_tag": "agent_saved_user_sessions",
"title": "AGENT | Autonomy business quality pack",
"question_type": "followup",
"broadness_level": "medium",
"turns": [
{
"user_message": "Сколько входящих денег за 2020 год по ООО Альтернатива Плюс без разреза по контрагентам?"
},
{
"user_message": "Сколько исходящих денег за 2020 год по ООО Альтернатива Плюс без разреза по контрагентам?"
},
{
"user_message": "А всего сколько денег пришло в ООО Альтернатива Плюс за 2020, без топов и без контрагентов?"
},
{
"user_message": "Теперь дай взрослый обзор за 2020 по компании: входящие, исходящие, нетто, топы, но банк в топах отдельно объясни как финансовый поток."
},
{
"user_message": "скока денег альтернатива заработала за 20 год?"
},
{
"user_message": "а это чистая прибыль?"
},
{
"user_message": "А отдельно по СБЕРБАНКУ: он для нас клиент, поставщик или финансовый поток? Дай коротко по подтвержденным строкам."
},
{
"user_message": "какое нетто по деньгам с Группа СВК за 2020 год: сколько получили и сколько заплатили?"
},
{
"user_message": "кому мы должны на конец 2020?"
},
{
"user_message": "а нам кто должен на конец 2020?"
},
{
"user_message": "сколько НДС надо заплатить в налоговую за декабрь 2019?"
},
{
"user_message": "Как ты оценишь деятельность компании?"
},
{
"user_message": "Какая номенклатура товара реализована с высокой прибылью какая с низкой?"
},
{
"user_message": "май 2020"
}
]
}
]
}