254 lines
14 KiB
JavaScript
254 lines
14 KiB
JavaScript
"use strict";
|
||
// @ts-nocheck
|
||
Object.defineProperty(exports, "__esModule", { value: true });
|
||
exports.buildInventoryHistoryCapabilityFollowupReply = buildInventoryHistoryCapabilityFollowupReply;
|
||
exports.buildAddressMemoryRecapReply = buildAddressMemoryRecapReply;
|
||
exports.buildSelectedObjectAnswerInspectionReply = buildSelectedObjectAnswerInspectionReply;
|
||
exports.resolveAssistantLivingChatMemoryContext = resolveAssistantLivingChatMemoryContext;
|
||
exports.createAssistantMemoryRecapPolicy = createAssistantMemoryRecapPolicy;
|
||
const assistantContinuityPolicy_1 = require("./assistantContinuityPolicy");
|
||
function toNonEmptyString(value) {
|
||
if (value === null || value === undefined) {
|
||
return null;
|
||
}
|
||
const text = String(value).trim();
|
||
return text.length > 0 ? text : null;
|
||
}
|
||
function collectMessageSamples(input) {
|
||
const values = [
|
||
input.rawUserMessage,
|
||
input.repairedRawUserMessage,
|
||
input.effectiveAddressUserMessage,
|
||
input.repairedEffectiveAddressUserMessage
|
||
];
|
||
return Array.from(new Set(values
|
||
.map((item) => String(item ?? "").trim())
|
||
.filter((item) => item.length > 0)));
|
||
}
|
||
function hasSignalAcrossSamples(samples, detector) {
|
||
return samples.some((sample) => detector(sample));
|
||
}
|
||
function hasExplicitRecapPromptSignal(samples) {
|
||
return samples.some((sample) => /(?:что\s+мы\s+.*(?:обсуждали|выяснили)|что\s+уже\s+выяснили|что\s+уже\s+поняли|напомни\s+что\s+мы)/iu.test(sample));
|
||
}
|
||
function buildInventoryHistoryCapabilityFollowupReply(input) {
|
||
const contextFacts = (0, assistantContinuityPolicy_1.resolveAddressDebugContextFacts)(input.addressDebug, input.toNonEmptyString);
|
||
const organization = input.organization ?? contextFacts.organization;
|
||
const lastAsOfDate = contextFacts.scopedDate;
|
||
const organizationPart = organization ? ` по компании «${organization}»` : "";
|
||
const referenceLine = lastAsOfDate
|
||
? `Да, могу. Сейчас мы уже смотрели складской срез${organizationPart} на ${lastAsOfDate}.`
|
||
: `Да, могу показать исторические данные${organizationPart} в этом же складском контуре.`;
|
||
return [
|
||
referenceLine,
|
||
`Могу показать исторические остатки${organizationPart} за нужный месяц, дату или год.`,
|
||
"Например:",
|
||
"- `на март 2020`",
|
||
"- `на июнь 2016`",
|
||
"- `за 2017 год`",
|
||
"- `сравни июнь 2016 с текущим срезом`",
|
||
"Если хочешь, сразу покажу нужный исторический период."
|
||
].join("\n");
|
||
}
|
||
function normalizeRecapIdentity(value) {
|
||
return String(value ?? "")
|
||
.trim()
|
||
.toLowerCase()
|
||
.replace(/[«»"'`]/g, "")
|
||
.replace(/\s+/g, " ");
|
||
}
|
||
function buildRecapFactLine(input) {
|
||
const detectedIntent = String(input.debug?.detected_intent ?? "");
|
||
const scopedDate = (0, assistantContinuityPolicy_1.resolveAddressDebugContextFacts)(input.debug).scopedDate;
|
||
const itemPart = input.item ? `по позиции «${input.item}»` : null;
|
||
const organizationPart = input.organization ? `по компании «${input.organization}»` : null;
|
||
const datePart = scopedDate ? ` на ${scopedDate}` : "";
|
||
if (detectedIntent === "inventory_on_hand_as_of_date") {
|
||
return `смотрели остатки${organizationPart ? ` ${organizationPart}` : ""}${datePart}`.trim();
|
||
}
|
||
if (detectedIntent === "inventory_purchase_provenance_for_item" && itemPart) {
|
||
return `разобрали, кто поставлял ${itemPart}${datePart}`.trim();
|
||
}
|
||
if (detectedIntent === "inventory_purchase_documents_for_item" && itemPart) {
|
||
return `подняли документы закупки ${itemPart}${datePart}`.trim();
|
||
}
|
||
if (detectedIntent === "inventory_sale_trace_for_item" && itemPart) {
|
||
return `разобрали, кому продавали ${itemPart}${datePart}`.trim();
|
||
}
|
||
if (detectedIntent === "inventory_purchase_to_sale_chain" && itemPart) {
|
||
return `проследили цепочку от закупки до продажи ${itemPart}${datePart}`.trim();
|
||
}
|
||
if (detectedIntent === "inventory_profitability_for_item" && itemPart) {
|
||
return `смотрели рентабельность ${itemPart}${datePart}`.trim();
|
||
}
|
||
if (detectedIntent === "inventory_aging_by_purchase_date" && itemPart) {
|
||
return `смотрели возраст остатков ${itemPart}${datePart}`.trim();
|
||
}
|
||
if (detectedIntent === "counterparty_activity_lifecycle" && organizationPart) {
|
||
return `смотрели активность в базе 1С ${organizationPart}`.trim();
|
||
}
|
||
if (detectedIntent === "list_documents_by_counterparty" && organizationPart) {
|
||
return `поднимали документы ${organizationPart}${datePart}`.trim();
|
||
}
|
||
return null;
|
||
}
|
||
function collectRecentRecapFacts(input) {
|
||
const sessionItems = Array.isArray(input.sessionItems) ? input.sessionItems : [];
|
||
if (sessionItems.length === 0) {
|
||
return [];
|
||
}
|
||
const currentItemKey = normalizeRecapIdentity(input.item);
|
||
const currentOrganizationKey = normalizeRecapIdentity(input.organization);
|
||
const facts = [];
|
||
const seen = new Set();
|
||
for (let index = sessionItems.length - 1; index >= 0; index -= 1) {
|
||
const item = sessionItems[index];
|
||
if (!item || item.role !== "assistant" || !item.debug || typeof item.debug !== "object") {
|
||
continue;
|
||
}
|
||
if (!(0, assistantContinuityPolicy_1.isGroundedAddressDebug)(item.debug, input.toNonEmptyString)) {
|
||
continue;
|
||
}
|
||
const debugContext = (0, assistantContinuityPolicy_1.resolveAddressDebugContextFacts)(item.debug, input.toNonEmptyString);
|
||
const debugItem = debugContext.item;
|
||
const debugOrganization = debugContext.organization;
|
||
const itemMatches = currentItemKey ? normalizeRecapIdentity(debugItem) === currentItemKey : false;
|
||
const organizationMatches = currentOrganizationKey
|
||
? normalizeRecapIdentity(debugOrganization) === currentOrganizationKey
|
||
: false;
|
||
if (currentItemKey && !itemMatches) {
|
||
continue;
|
||
}
|
||
if (!currentItemKey && currentOrganizationKey && !organizationMatches) {
|
||
continue;
|
||
}
|
||
const fact = buildRecapFactLine({
|
||
debug: item.debug,
|
||
item: debugItem,
|
||
organization: debugOrganization
|
||
});
|
||
if (!fact || seen.has(fact)) {
|
||
continue;
|
||
}
|
||
seen.add(fact);
|
||
facts.push(fact);
|
||
if (facts.length >= 3) {
|
||
break;
|
||
}
|
||
}
|
||
return facts.reverse();
|
||
}
|
||
function buildAddressMemoryRecapReply(input) {
|
||
const contextFacts = (0, assistantContinuityPolicy_1.resolveAddressDebugContextFacts)(input.addressDebug, input.toNonEmptyString);
|
||
const item = contextFacts.item;
|
||
const organization = input.organization ?? contextFacts.organization;
|
||
const scopedDate = contextFacts.scopedDate;
|
||
const recapFacts = collectRecentRecapFacts({
|
||
sessionItems: input.sessionItems,
|
||
item,
|
||
organization,
|
||
toNonEmptyString: input.toNonEmptyString
|
||
});
|
||
if (item) {
|
||
if (recapFacts.length > 0) {
|
||
const datePart = scopedDate ? ` в срезе на ${scopedDate}` : "";
|
||
const organizationPart = organization ? ` по компании «${organization}»` : "";
|
||
return [
|
||
`Да, помню. По позиции «${item}»${organizationPart}${datePart} мы уже выяснили:`,
|
||
...recapFacts.map((fact) => `- ${fact}.`),
|
||
"Могу сразу продолжить по ней: поставщик, закупка, документы или продажа."
|
||
].join("\n");
|
||
}
|
||
const datePart = scopedDate ? ` в срезе на ${scopedDate}` : "";
|
||
const organizationPart = organization ? ` по компании «${organization}»` : "";
|
||
return [
|
||
`Да, помню. Мы обсуждали позицию «${item}»${organizationPart}${datePart}.`,
|
||
"Могу продолжить по ней без переписывания сущности: кто поставил, когда купили, по каким документам или кому продали."
|
||
].join(" ");
|
||
}
|
||
if (organization || scopedDate) {
|
||
const organizationPart = organization ? ` по компании «${organization}»` : "";
|
||
const datePart = scopedDate ? ` на ${scopedDate}` : "";
|
||
return [
|
||
`Да, помню. Мы уже смотрели адресный контур${organizationPart}${datePart}.`,
|
||
"Могу кратко напомнить контекст или сразу продолжить следующий шаг по этому же сценарию."
|
||
].join(" ");
|
||
}
|
||
return "Да, помню предыдущий адресный контур. Могу кратко напомнить, что мы уже подтвердили, или сразу продолжить следующий шаг.";
|
||
}
|
||
function buildSelectedObjectAnswerInspectionReply(input) {
|
||
const contextFacts = (0, assistantContinuityPolicy_1.resolveAddressDebugContextFacts)(input.addressDebug, input.toNonEmptyString);
|
||
const itemLabel = contextFacts.item ?? "эта позиция";
|
||
const detectedIntent = String(input.addressDebug?.detected_intent ?? "");
|
||
if (detectedIntent === "inventory_sale_trace_for_item") {
|
||
return [
|
||
`Да, если так прозвучало, это ошибка чтения ответа. «${itemLabel}» здесь не контрагент, а сама позиция, по которой мы смотрели продажу.`,
|
||
"В предыдущем ответе я показывал документы выбытия по этой позиции. Покупатель в доступных данных отдельно не выделен, поэтому назвать контрагента-покупателя я там не мог.",
|
||
"Если хочешь, следующим шагом могу отдельно проверить, можно ли вытащить покупателя по связанным документам реализации."
|
||
].join(" ");
|
||
}
|
||
if (detectedIntent === "inventory_purchase_provenance_for_item" ||
|
||
detectedIntent === "inventory_purchase_documents_for_item") {
|
||
return [
|
||
`Да, если так прозвучало, это ошибка чтения ответа. «${itemLabel}» здесь не контрагент, а сама позиция или номенклатура.`,
|
||
"В предыдущем ответе речь шла о закупке этой позиции: я перечислял поставщиков или закупочные документы по ней, а не называл саму позицию контрагентом."
|
||
].join(" ");
|
||
}
|
||
return [
|
||
`Да, если так прозвучало, это ошибка чтения ответа. «${itemLabel}» здесь не контрагент, а выбранный объект разбора.`,
|
||
"Я сейчас уточняю именно смысл предыдущего grounded-ответа по этой позиции, а не запускаю новый адресный поиск."
|
||
].join(" ");
|
||
}
|
||
function resolveAssistantLivingChatMemoryContext(input) {
|
||
const contextualInventoryHistoryCapabilityFollowup = String(input.modeDecisionReason ?? "") === "inventory_history_capability_followup_detected";
|
||
const contextualMemoryRecapFollowup = String(input.modeDecisionReason ?? "") === "memory_recap_followup_detected";
|
||
const contextualAnswerInspectionFollowup = String(input.modeDecisionReason ?? "") === "answer_inspection_followup_detected";
|
||
const continuity = (0, assistantContinuityPolicy_1.resolveAssistantContinuitySnapshot)({
|
||
sessionItems: input.sessionItems,
|
||
toNonEmptyString
|
||
});
|
||
return {
|
||
contextualInventoryHistoryCapabilityFollowup,
|
||
contextualMemoryRecapFollowup,
|
||
contextualAnswerInspectionFollowup,
|
||
lastGroundedInventoryAddressDebug: contextualInventoryHistoryCapabilityFollowup
|
||
? continuity.lastGroundedInventoryAddressDebug
|
||
: null,
|
||
lastMemoryAddressDebug: contextualMemoryRecapFollowup
|
||
? continuity.lastGroundedItemAddressDebug ?? continuity.lastGroundedAddressDebug
|
||
: null,
|
||
lastAnswerInspectionAddressDebug: contextualAnswerInspectionFollowup
|
||
? continuity.lastGroundedItemAddressDebug ?? continuity.lastGroundedAddressDebug
|
||
: null
|
||
};
|
||
}
|
||
function createAssistantMemoryRecapPolicy(deps) {
|
||
function resolveRouteMemorySignals(input) {
|
||
const samples = collectMessageSamples(input);
|
||
const continuity = (0, assistantContinuityPolicy_1.resolveAssistantContinuitySnapshot)({
|
||
sessionItems: input.sessionItems,
|
||
toNonEmptyString
|
||
});
|
||
const groundedInventoryContext = continuity.lastGroundedInventoryAddressDebug ?? input.lastGroundedAddressDebug;
|
||
const historicalCapabilitySignal = hasSignalAcrossSamples(samples, deps.hasHistoricalCapabilityFollowupSignal);
|
||
const memoryRecapSignal = hasSignalAcrossSamples(samples, deps.hasConversationMemoryRecallFollowupSignal);
|
||
const explicitRecapPromptSignal = hasExplicitRecapPromptSignal(samples);
|
||
return {
|
||
contextualHistoricalCapabilityFollowupDetected: Boolean(input.capabilityMetaQuery &&
|
||
!input.dataScopeMetaQuery &&
|
||
!input.dataRetrievalSignal &&
|
||
historicalCapabilitySignal &&
|
||
deps.isGroundedInventoryContextDebug(groundedInventoryContext)),
|
||
contextualMemoryRecapFollowupDetected: Boolean(!input.dataScopeMetaQuery &&
|
||
!input.capabilityMetaQuery &&
|
||
!input.aggregateBusinessAnalyticsSignal &&
|
||
memoryRecapSignal &&
|
||
(explicitRecapPromptSignal || (!input.dataRetrievalSignal && !input.strongDataSignal)) &&
|
||
continuity.hasGroundedAddressContext)
|
||
};
|
||
}
|
||
return {
|
||
resolveRouteMemorySignals
|
||
};
|
||
}
|