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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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