Закрепить phase5 continuity replay для 1С

This commit is contained in:
dctouch 2026-05-23 19:46:32 +03:00
parent 624e0cdf26
commit b2fe0460b3
7 changed files with 37 additions and 73 deletions

View File

@ -10,109 +10,75 @@
"step_id": "step_01_smalltalk", "step_id": "step_01_smalltalk",
"title": "Casual opening stays human", "title": "Casual opening stays human",
"question": "привет, как дела?", "question": "привет, как дела?",
"semantic_tags": [ "semantic_tags": ["meta_smalltalk"]
"meta_smalltalk"
]
}, },
{ {
"step_id": "step_02_data_scope_meta", "step_id": "step_02_data_scope_meta",
"title": "Data-scope question shows available companies", "title": "Data-scope question shows available companies",
"question": "по какой компании мы сейчас работаем?", "question": "по какой компании мы сейчас работаем?",
"semantic_tags": [ "semantic_tags": ["meta_scope"]
"meta_scope"
]
}, },
{ {
"step_id": "step_03_inventory_root_requires_company", "step_id": "step_03_inventory_root_requires_company",
"title": "Inventory root correctly asks to choose a company", "title": "Inventory root correctly asks to choose a company",
"question": "какие остатки на складе на март 2021", "question": "какие остатки на складе на март 2021",
"semantic_tags": [ "semantic_tags": ["inventory_root", "company_clarification"]
"inventory_root",
"company_clarification"
]
}, },
{ {
"step_id": "step_04_choose_company", "step_id": "step_04_choose_company",
"title": "User selects the company inside the same session", "title": "User selects the company inside the same session",
"question": "давай по Альтернативе Плюс", "question": "давай по Альтернативе Плюс",
"semantic_tags": [ "semantic_tags": ["meta_scope", "company_selection"]
"meta_scope",
"company_selection"
]
}, },
{ {
"step_id": "step_05_inventory_root_after_company", "step_id": "step_05_inventory_root_after_company",
"title": "Inventory root continues after the company choice", "title": "Inventory root continues after the company choice",
"question": "тогда покажи остатки на март 2021", "question": "тогда покажи остатки на март 2021",
"semantic_tags": [ "semantic_tags": ["inventory_root", "company_selected"]
"inventory_root",
"company_selected"
]
}, },
{ {
"step_id": "step_06_selected_item_supplier", "step_id": "step_06_selected_item_supplier",
"title": "Selected-object supplier follow-up survives after company selection", "title": "Selected-object supplier follow-up survives after company selection",
"question": "По выбранному объекту \"Столешница 600*3050*26 альмандин\": кто нам это поставил?", "question": "По выбранному объекту \"Столешница 600*3050*26 альмандин\": кто нам это поставил?",
"semantic_tags": [ "semantic_tags": ["selected_object", "selected_object_supplier"]
"selected_object",
"selected_object_supplier"
]
}, },
{ {
"step_id": "step_07_selected_item_documents", "step_id": "step_07_selected_item_documents",
"title": "Selected-object documents stay in the same contour", "title": "Selected-object documents stay in the same contour",
"question": "По выбранному объекту \"Столешница 600*3050*26 альмандин\": покажи документы по этой позиции", "question": "По выбранному объекту \"Столешница 600*3050*26 альмандин\": покажи документы по этой позиции",
"semantic_tags": [ "semantic_tags": ["selected_object", "selected_object_documents"]
"selected_object",
"selected_object_documents"
]
}, },
{ {
"step_id": "step_08_inventory_same_date_restore", "step_id": "step_08_inventory_same_date_restore",
"title": "Same-date restore returns to the inventory root within the chosen company", "title": "Same-date restore returns to the inventory root within the chosen company",
"question": "покажи еще раз остатки на эту же дату", "question": "покажи еще раз остатки на эту же дату",
"semantic_tags": [ "semantic_tags": ["inventory_root", "same_date_restore"]
"inventory_root",
"same_date_restore"
]
}, },
{ {
"step_id": "step_09_company_activity_age", "step_id": "step_09_company_activity_age",
"title": "Organization age should be answered through reachable activity evidence or honest boundedness", "title": "Organization age should be answered through reachable activity evidence or honest boundedness",
"allowed_reply_types": [ "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"],
"factual", "expected_intents": ["counterparty_activity_lifecycle"],
"factual_with_explanation",
"partial_coverage"
],
"expected_intents": [
"counterparty_activity_lifecycle"
],
"expected_recipe": "address_counterparty_activity_lifecycle_v1", "expected_recipe": "address_counterparty_activity_lifecycle_v1",
"required_direct_answer_patterns_any": [ "required_direct_answer_patterns_any": [
"(?i)РїРѕ активности", "(?i)по активности",
"(?i)первая подтвержденная активность|РЅРµ удается точно определить" "(?i)первая подтвержденная активность|не удается точно определить"
], ],
"forbidden_direct_answer_patterns": [ "forbidden_direct_answer_patterns": [
"(?i)РЅРµ найден контрагент", "(?i)не найден контрагент",
"(?i)уточните точное наименование организации" "(?i)уточните точное наименование организации"
], ],
"criticality": "critical", "criticality": "critical",
"question": "а по Альтернативе Плюс сколько лет активности в базе 1С?", "question": "а по Альтернативе Плюс сколько лет активности в базе 1С?",
"semantic_tags": [ "semantic_tags": ["organization_activity_age", "company_selected"]
"organization_activity_age",
"company_selected"
]
}, },
{ {
"step_id": "step_10_capability_meta_interrupt", "step_id": "step_10_capability_meta_interrupt",
"title": "Capability meta interrupt does not destroy prior context", "title": "Capability meta interrupt does not destroy prior context",
"allowed_reply_types": [ "allowed_reply_types": ["factual_with_explanation", "factual"],
"factual_with_explanation",
"factual"
],
"required_direct_answer_patterns_any": [ "required_direct_answer_patterns_any": [
"(?i)1СЃ", "(?i)1с",
"(?i)РЅРґСЃ|контрагент|остатк|склад" "(?i)ндс|контрагент|остатк|склад"
], ],
"forbidden_direct_answer_patterns": [ "forbidden_direct_answer_patterns": [
"(?i)vat_period_snapshot", "(?i)vat_period_snapshot",
@ -124,34 +90,25 @@
], ],
"criticality": "warning", "criticality": "warning",
"question": "что ты умеешь?", "question": "что ты умеешь?",
"semantic_tags": [ "semantic_tags": ["meta_capability"]
"meta_capability"
]
}, },
{ {
"step_id": "step_11_memory_recap_after_interrupts", "step_id": "step_11_memory_recap_after_interrupts",
"title": "Memory recap still remembers the selected object after capability interrupt", "title": "Memory recap still remembers the selected object after capability interrupt",
"question": "а ты помнишь, что мы по этой позиции уже выяснили?", "question": "а ты помнишь, что мы по этой позиции уже выяснили?",
"semantic_tags": [ "semantic_tags": ["meta_memory"]
"meta_memory"
]
}, },
{ {
"step_id": "step_12_receivables_march_2020", "step_id": "step_12_receivables_march_2020",
"title": "Cross-domain pivot keeps the active company", "title": "Cross-domain pivot keeps the active company",
"question": "кто нам должен на март 2020", "question": "кто нам должен на март 2020",
"semantic_tags": [ "semantic_tags": ["settlements_receivables"]
"settlements_receivables"
]
}, },
{ {
"step_id": "step_13_inventory_same_date_cross_domain", "step_id": "step_13_inventory_same_date_cross_domain",
"title": "Inventory same-date pivot should reuse the root date inside the active company", "title": "Inventory same-date pivot should reuse the root date inside the active company",
"question": "остатки по складу на эту же дату", "question": "остатки по складу на эту же дату",
"semantic_tags": [ "semantic_tags": ["inventory_root", "same_date_pivot"]
"inventory_root",
"same_date_pivot"
]
} }
] ]
} }

View File

@ -20,6 +20,9 @@ function groupRowsByMarker(rows) {
function formatOptionalDate(value, formatDateRu) { function formatOptionalDate(value, formatDateRu) {
return value ? formatDateRu(value) : "дата не указана"; return value ? formatDateRu(value) : "дата не указана";
} }
function trimTrailingSentenceDot(value) {
return value ? value.replace(/\.+$/u, "") : null;
}
function findFocusedCounterpartyValuePoint(profileRows, counterpartyHint, deps) { function findFocusedCounterpartyValuePoint(profileRows, counterpartyHint, deps) {
if (!counterpartyHint) { if (!counterpartyHint) {
return null; return null;
@ -252,7 +255,7 @@ function composeCounterpartyAnalyticsReply(intent, rows, options = {}, deps) {
: null; : null;
const lines = [ const lines = [
observedAgeLabel && firstObservedActivity && lastObservedActivity observedAgeLabel && firstObservedActivity && lastObservedActivity
? `По активности в базе 1С контрагент ${focusedCounterparty.name} наблюдается минимум ${observedAgeLabel}.` ? `По активности в базе 1С контрагент ${focusedCounterparty.name} наблюдается минимум ${trimTrailingSentenceDot(observedAgeLabel)}.`
: `По активности в базе 1С контрагент ${focusedCounterparty.name} найден в подтвержденных движениях.` : `По активности в базе 1С контрагент ${focusedCounterparty.name} найден в подтвержденных движениях.`
]; ];
if (firstObservedActivity) { if (firstObservedActivity) {
@ -311,7 +314,7 @@ function composeCounterpartyAnalyticsReply(intent, rows, options = {}, deps) {
: null; : null;
const lines = [ const lines = [
observedAgeLabel && organizationFirstObservedActivity && organizationLastObservedActivity observedAgeLabel && organizationFirstObservedActivity && organizationLastObservedActivity
? `По активности организации ${organizationHint} в базе 1С наблюдается минимум ${observedAgeLabel}.` ? `По активности организации ${organizationHint} в базе 1С наблюдается минимум ${trimTrailingSentenceDot(observedAgeLabel)}.`
: `По активности организации ${organizationHint} в базе 1С найдены подтвержденные движения.` : `По активности организации ${organizationHint} в базе 1С найдены подтвержденные движения.`
]; ];
if (organizationFirstObservedActivity) { if (organizationFirstObservedActivity) {

View File

@ -4090,7 +4090,7 @@ function buildAssistantCapabilityContractReply(userMessage = "") {
.replace(/По основным группам:/giu, "Основные направления:") .replace(/По основным группам:/giu, "Основные направления:")
.replace(/Если нужно, подскажу, как лучше сформулировать запрос под вашу задачу\./giu, "Если хотите, можно сразу задать конкретный вопрос по документам, остаткам, НДС, контрагенту или договору.") .replace(/Если нужно, подскажу, как лучше сформулировать запрос под вашу задачу\./giu, "Если хотите, можно сразу задать конкретный вопрос по документам, остаткам, НДС, контрагенту или договору.")
.replace(/Что не делаю:\s*/giu, "Не делаю только административные действия: ") .replace(/Что не делаю:\s*/giu, "Не делаю только административные действия: ")
.replace(/\s{2,}/g, " ") .replace(/[^\S\r\n]{2,}/g, " ")
.replace(/\n{3,}/g, "\n\n") .replace(/\n{3,}/g, "\n\n")
.trim(); .trim();
return normalizedReply || "Могу помогать с вопросами по данным 1С: НДС, контрагенты, долги, деньги, договоры и склад."; return normalizedReply || "Могу помогать с вопросами по данным 1С: НДС, контрагенты, долги, деньги, договоры и склад.";

View File

@ -199,7 +199,7 @@ function loadCapabilitiesRegistry() {
} }
function buildCapabilityContractReplyFromRegistry() { function buildCapabilityContractReplyFromRegistry() {
return [ return [
"Могу быстро смотреть управленческие вещи по данным 1С в режиме чтения.", "Могу помочь с быстрым анализом данных 1С:",
"", "",
"- кто должен денег и кому должны;", "- кто должен денег и кому должны;",
"- какой год или месяц был самым денежным;", "- какой год или месяц был самым денежным;",

View File

@ -105,6 +105,10 @@ function formatOptionalDate(value: string | null, formatDateRu: (isoDate: string
return value ? formatDateRu(value) : "дата не указана"; return value ? formatDateRu(value) : "дата не указана";
} }
function trimTrailingSentenceDot(value: string | null): string | null {
return value ? value.replace(/\.+$/u, "") : null;
}
function findFocusedCounterpartyValuePoint( function findFocusedCounterpartyValuePoint(
profileRows: CounterpartyValuePoint[], profileRows: CounterpartyValuePoint[],
counterpartyHint: string | null | undefined, counterpartyHint: string | null | undefined,
@ -371,7 +375,7 @@ export function composeCounterpartyAnalyticsReply(
: null; : null;
const lines: string[] = [ const lines: string[] = [
observedAgeLabel && firstObservedActivity && lastObservedActivity observedAgeLabel && firstObservedActivity && lastObservedActivity
? `По активности в базе 1С контрагент ${focusedCounterparty.name} наблюдается минимум ${observedAgeLabel}.` ? `По активности в базе 1С контрагент ${focusedCounterparty.name} наблюдается минимум ${trimTrailingSentenceDot(observedAgeLabel)}.`
: `По активности в базе 1С контрагент ${focusedCounterparty.name} найден в подтвержденных движениях.` : `По активности в базе 1С контрагент ${focusedCounterparty.name} найден в подтвержденных движениях.`
]; ];
if (firstObservedActivity) { if (firstObservedActivity) {
@ -433,7 +437,7 @@ export function composeCounterpartyAnalyticsReply(
: null; : null;
const lines: string[] = [ const lines: string[] = [
observedAgeLabel && organizationFirstObservedActivity && organizationLastObservedActivity observedAgeLabel && organizationFirstObservedActivity && organizationLastObservedActivity
? `По активности организации ${organizationHint} в базе 1С наблюдается минимум ${observedAgeLabel}.` ? `По активности организации ${organizationHint} в базе 1С наблюдается минимум ${trimTrailingSentenceDot(observedAgeLabel)}.`
: `По активности организации ${organizationHint} в базе 1С найдены подтвержденные движения.` : `По активности организации ${organizationHint} в базе 1С найдены подтвержденные движения.`
]; ];
if (organizationFirstObservedActivity) { if (organizationFirstObservedActivity) {

View File

@ -4047,7 +4047,7 @@ function buildAssistantCapabilityContractReply(userMessage = "") {
.replace(/По основным группам:/giu, "Основные направления:") .replace(/По основным группам:/giu, "Основные направления:")
.replace(/Если нужно, подскажу, как лучше сформулировать запрос под вашу задачу\./giu, "Если хотите, можно сразу задать конкретный вопрос по документам, остаткам, НДС, контрагенту или договору.") .replace(/Если нужно, подскажу, как лучше сформулировать запрос под вашу задачу\./giu, "Если хотите, можно сразу задать конкретный вопрос по документам, остаткам, НДС, контрагенту или договору.")
.replace(/Что не делаю:\s*/giu, "Не делаю только административные действия: ") .replace(/Что не делаю:\s*/giu, "Не делаю только административные действия: ")
.replace(/\s{2,}/g, " ") .replace(/[^\S\r\n]{2,}/g, " ")
.replace(/\n{3,}/g, "\n\n") .replace(/\n{3,}/g, "\n\n")
.trim(); .trim();
return normalizedReply || "Могу помогать с вопросами по данным 1С: НДС, контрагенты, долги, деньги, договоры и склад."; return normalizedReply || "Могу помогать с вопросами по данным 1С: НДС, контрагенты, долги, деньги, договоры и склад.";

View File

@ -220,7 +220,7 @@ export function loadCapabilitiesRegistry(): CapabilityRegistry {
export function buildCapabilityContractReplyFromRegistry(): string { export function buildCapabilityContractReplyFromRegistry(): string {
return [ return [
"Могу быстро смотреть управленческие вещи по данным 1С в режиме чтения.", "Могу помочь с быстрым анализом данных 1С:",
"", "",
"- кто должен денег и кому должны;", "- кто должен денег и кому должны;",
"- какой год или месяц был самым денежным;", "- какой год или месяц был самым денежным;",