Закрепить ответы ассистента по бизнес-зависимостям
This commit is contained in:
@@ -2558,6 +2558,17 @@ function resolveUnicodeAddressIntentBridge(text: string): AddressIntentResolutio
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
/(?:поставщик|закуп|исходящ|плат[её]ж|supplier|vendor|procurement|outgoing|payout)/iu.test(normalized) &&
|
||||
/(?:зависим|завязан|концентрац|ключев|основн|критич|dependency|concentration|key|critical)/iu.test(normalized)
|
||||
) {
|
||||
return unicodeBridgeResolution(
|
||||
"unknown",
|
||||
"high",
|
||||
"unicode_business_overview_supplier_quality_deferred_to_discovery"
|
||||
);
|
||||
}
|
||||
|
||||
if (hasDocumentCue && (hasCounterpartyCue || hasLooseCounterpartyByAnchor) && !hasContractCue) {
|
||||
return unicodeBridgeResolution(
|
||||
"list_documents_by_counterparty",
|
||||
|
||||
@@ -99,6 +99,7 @@ interface AddressTryHandleOptions {
|
||||
llmSemanticHints?: AddressLlmSemanticHints | null;
|
||||
activeOrganization?: string | null;
|
||||
knownOrganizations?: string[];
|
||||
rawUserMessage?: string | null;
|
||||
}
|
||||
|
||||
interface AddressCapabilityAudit {
|
||||
@@ -3943,6 +3944,10 @@ export class AddressQueryService {
|
||||
shadowRouteAudit
|
||||
});
|
||||
}
|
||||
const rawUserMessageForReply =
|
||||
typeof options.rawUserMessage === "string" && options.rawUserMessage.trim().length > 0
|
||||
? options.rawUserMessage
|
||||
: undefined;
|
||||
const composeOptionsFromFilters = (
|
||||
filterSet: AddressFilterSet,
|
||||
options: {
|
||||
@@ -3951,9 +3956,14 @@ export class AddressQueryService {
|
||||
useRubCurrency?: boolean;
|
||||
counterpartyHint?: string;
|
||||
accountHint?: string;
|
||||
rawUserMessage?: string | null;
|
||||
} = {}
|
||||
) => ({
|
||||
userMessage,
|
||||
rawUserMessage:
|
||||
typeof options.rawUserMessage === "string" && options.rawUserMessage.trim().length > 0
|
||||
? options.rawUserMessage
|
||||
: rawUserMessageForReply,
|
||||
itemHint: typeof filterSet.item === "string" ? filterSet.item : undefined,
|
||||
counterpartyHint:
|
||||
typeof options.counterpartyHint === "string"
|
||||
|
||||
+24
-5
@@ -548,7 +548,11 @@ export function composeCounterpartyAnalyticsReply(
|
||||
const focus = deps.detectValueRankingFocus(options.userMessage);
|
||||
const limit = deps.detectRankingLimit(options.userMessage, 20);
|
||||
const minOpsForAvgCheck = deps.detectMinOpsForAvgCheck(options.userMessage);
|
||||
const normalizedQuestion = deps.normalizeQuestionText(options.userMessage);
|
||||
const questionSignalText = [options.rawUserMessage, options.userMessage]
|
||||
.map((value) => String(value ?? "").trim())
|
||||
.filter(Boolean)
|
||||
.join(" ");
|
||||
const normalizedQuestion = deps.normalizeQuestionText(questionSignalText || options.userMessage);
|
||||
const asksSingleBestCounterparty =
|
||||
focus === "top_by_total" &&
|
||||
/(?:какой|кто|which|who|какой|кто)/iu.test(normalizedQuestion) &&
|
||||
@@ -572,6 +576,10 @@ export function composeCounterpartyAnalyticsReply(
|
||||
const effectiveLimit = asksSingleBestCounterparty || semanticSingleBestCounterparty ? 1 : limit;
|
||||
const cashflowBoundaryLine = buildCashflowBoundaryLine(isSupplier);
|
||||
const cashflowNextStepLine = buildCashflowNextStepLine(isSupplier, normalizedQuestion);
|
||||
const dependencyCue =
|
||||
/(?:зависим|завязан|концентрац|ключев|основн|критич|dependency|concentration|key|critical)/iu.test(
|
||||
normalizedQuestion
|
||||
);
|
||||
|
||||
const byCounterparty = new Map<string, CounterpartyValuePoint>();
|
||||
const byYear = new Map<number, CounterpartyYearPoint>();
|
||||
@@ -864,13 +872,24 @@ export function composeCounterpartyAnalyticsReply(
|
||||
? `В выбранном срезе найден один поставщик: ${leadingCounterparty.name} (${deps.formatMoneyRub(leadingCounterparty.total)} по ${leadingCounterparty.ops} операциям). Это не полноценный сравнительный рейтинг.`
|
||||
: `В выбранном срезе найден один клиент: ${leadingCounterparty.name} (${deps.formatMoneyRub(leadingCounterparty.total)} по ${leadingCounterparty.ops} операциям). Это не полноценный сравнительный рейтинг.`
|
||||
: isSupplier
|
||||
? `Крупнейший поставщик по подтвержденным выплатам ${rankingPeriodLabel}: ${leadingCounterparty.name} (${deps.formatMoneyRub(leadingCounterparty.total)} по ${leadingCounterparty.ops} операциям).`
|
||||
: `Самый доходный клиент ${rankingPeriodLabel} по подтвержденным поступлениям: ${leadingCounterparty.name} (${deps.formatMoneyRub(leadingCounterparty.total)} по ${leadingCounterparty.ops} операциям).`;
|
||||
? dependencyCue
|
||||
? `Главный сигнал зависимости по исходящим платежам ${rankingPeriodLabel}: ${leadingCounterparty.name} (${deps.formatMoneyRub(leadingCounterparty.total)} по ${leadingCounterparty.ops} операциям).`
|
||||
: `Крупнейший поставщик по подтвержденным выплатам ${rankingPeriodLabel}: ${leadingCounterparty.name} (${deps.formatMoneyRub(leadingCounterparty.total)} по ${leadingCounterparty.ops} операциям).`
|
||||
: dependencyCue
|
||||
? `Главный сигнал зависимости по входящим деньгам ${rankingPeriodLabel}: ${leadingCounterparty.name} (${deps.formatMoneyRub(leadingCounterparty.total)} по ${leadingCounterparty.ops} операциям).`
|
||||
: `Самый доходный клиент ${rankingPeriodLabel} по подтвержденным поступлениям: ${leadingCounterparty.name} (${deps.formatMoneyRub(leadingCounterparty.total)} по ${leadingCounterparty.ops} операциям).`;
|
||||
lines.unshift(directAnswerLine);
|
||||
if (dependencyCue) {
|
||||
lines.splice(
|
||||
1,
|
||||
0,
|
||||
"Это сигнал концентрации по найденным денежным строкам 1С, а не подтверждение договорной зависимости, надежности контрагента или чистой прибыли."
|
||||
);
|
||||
}
|
||||
if (!isSupplier) {
|
||||
lines.splice(1, 0, cashflowBoundaryLine);
|
||||
lines.splice(dependencyCue ? 2 : 1, 0, cashflowBoundaryLine);
|
||||
if (cashflowNextStepLine) {
|
||||
lines.splice(2, 0, cashflowNextStepLine);
|
||||
lines.splice(dependencyCue ? 3 : 2, 0, cashflowNextStepLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { AddressEvidenceStrength, AddressResponseType, AddressResultMode }
|
||||
|
||||
export interface ComposeFactualReplyOptions<TVatDirectSourceProbe = unknown> {
|
||||
userMessage?: string;
|
||||
rawUserMessage?: string;
|
||||
itemHint?: string;
|
||||
counterpartyHint?: string;
|
||||
organizationHint?: string;
|
||||
|
||||
@@ -224,6 +224,7 @@ export async function runAssistantAddressAttemptRuntime<ResponseType = unknown>(
|
||||
runAddressLaneAttemptRuntimeSafe(
|
||||
buildAssistantAddressLaneAttemptRuntimeInput({
|
||||
messageUsed,
|
||||
rawUserMessage: input.userMessage,
|
||||
carryMeta,
|
||||
analysisDateHint,
|
||||
llmSemanticHints,
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { RunAssistantAddressLaneAttemptRuntimeInput } from "./assistantAddr
|
||||
|
||||
export interface BuildAssistantAddressLaneAttemptRuntimeInputInput {
|
||||
messageUsed: RunAssistantAddressLaneAttemptRuntimeInput["messageUsed"];
|
||||
rawUserMessage: RunAssistantAddressLaneAttemptRuntimeInput["rawUserMessage"];
|
||||
carryMeta: RunAssistantAddressLaneAttemptRuntimeInput["carryMeta"];
|
||||
analysisDateHint: RunAssistantAddressLaneAttemptRuntimeInput["analysisDateHint"];
|
||||
llmSemanticHints: RunAssistantAddressLaneAttemptRuntimeInput["llmSemanticHints"];
|
||||
@@ -17,6 +18,7 @@ export function buildAssistantAddressLaneAttemptRuntimeInput(
|
||||
): RunAssistantAddressLaneAttemptRuntimeInput {
|
||||
return {
|
||||
messageUsed: input.messageUsed,
|
||||
rawUserMessage: input.rawUserMessage,
|
||||
carryMeta: input.carryMeta,
|
||||
analysisDateHint: input.analysisDateHint,
|
||||
llmSemanticHints: input.llmSemanticHints,
|
||||
|
||||
+3
-1
@@ -10,6 +10,7 @@ export function resolveAssistantAddressLaneAttemptFollowupContext(
|
||||
|
||||
export interface BuildAssistantAddressLaneAttemptQueryOptionsInput {
|
||||
analysisDateHint: RunAssistantAddressLaneAttemptRuntimeInput["analysisDateHint"];
|
||||
rawUserMessage: RunAssistantAddressLaneAttemptRuntimeInput["rawUserMessage"];
|
||||
scopedFollowupContext: Record<string, unknown> | null;
|
||||
llmSemanticHints: RunAssistantAddressLaneAttemptRuntimeInput["llmSemanticHints"];
|
||||
activeOrganization: RunAssistantAddressLaneAttemptRuntimeInput["activeOrganization"];
|
||||
@@ -20,7 +21,8 @@ export function buildAssistantAddressLaneAttemptQueryOptions(
|
||||
input: BuildAssistantAddressLaneAttemptQueryOptionsInput
|
||||
): Parameters<RunAssistantAddressLaneAttemptRuntimeInput["runAddressQueryTryHandle"]>[1] {
|
||||
const base = {
|
||||
analysisDateHint: input.analysisDateHint
|
||||
analysisDateHint: input.analysisDateHint,
|
||||
rawUserMessage: input.rawUserMessage ?? undefined
|
||||
} as Parameters<RunAssistantAddressLaneAttemptRuntimeInput["runAddressQueryTryHandle"]>[1];
|
||||
if (input.scopedFollowupContext) {
|
||||
base.followupContext = input.scopedFollowupContext;
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
|
||||
export interface RunAssistantAddressLaneAttemptRuntimeInput {
|
||||
messageUsed: string;
|
||||
rawUserMessage?: string | null;
|
||||
carryMeta: AssistantAddressCarryoverLike | null;
|
||||
analysisDateHint: string | null;
|
||||
llmSemanticHints?: Record<string, unknown> | null;
|
||||
@@ -24,6 +25,7 @@ export interface RunAssistantAddressLaneAttemptRuntimeInput {
|
||||
llmSemanticHints?: Record<string, unknown> | null;
|
||||
activeOrganization?: string | null;
|
||||
knownOrganizations?: string[];
|
||||
rawUserMessage?: string | null;
|
||||
}
|
||||
) => Promise<AssistantAddressLaneLike | null>;
|
||||
}
|
||||
@@ -43,7 +45,8 @@ export async function runAssistantAddressLaneAttemptRuntime(
|
||||
scopedFollowupContext,
|
||||
llmSemanticHints: input.llmSemanticHints ?? null,
|
||||
activeOrganization: input.activeOrganization,
|
||||
knownOrganizations: input.knownOrganizations
|
||||
knownOrganizations: input.knownOrganizations,
|
||||
rawUserMessage: input.rawUserMessage ?? input.messageUsed
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@@ -107,6 +107,16 @@ function requestsCounterpartyLeaderSurface(
|
||||
return /(?:(?:кто|как\p{L}*|покаж\p{L}*|назов\p{L}*|раскро\p{L}*)[\s\S]{0,100}(?:главн\p{L}*|крупнейш\p{L}*|основн\p{L}*|ведущ\p{L}*|топ)[\s\S]{0,80}(?:клиент|заказчик|поставщик|получател)|(?:главн\p{L}*|крупнейш\p{L}*|основн\p{L}*|ведущ\p{L}*)[\s\S]{0,80}(?:клиент|заказчик|поставщик|получател)|(?:топ[-\s]*(?:клиент|заказчик|поставщик|получател))|(?:клиент|поставщик)[\s\S]{0,80}(?:главн|крупнейш|основн|ведущ|топ))/iu.test(text);
|
||||
}
|
||||
|
||||
function requestsBusinessOverviewNextChecks(
|
||||
turnMeaning: Record<string, unknown> | null,
|
||||
graph: Record<string, unknown> | null
|
||||
): boolean {
|
||||
const text = normalizedTurnAndGraphText(turnMeaning, graph);
|
||||
return /(?:что\s+(?:дальше\s+)?провер\w*|что\s+провер\w*\s+дальше|следующ\w*\s+шаг|в\s+первую\s+очередь\s+провер\w*|next\s+checks?|next\s+steps?)/iu.test(
|
||||
text
|
||||
);
|
||||
}
|
||||
|
||||
function requestsCompactCashflowAnswer(
|
||||
turnMeaning: Record<string, unknown> | null,
|
||||
graph: Record<string, unknown> | null
|
||||
@@ -527,6 +537,14 @@ function businessOverviewPeriodText(overview: Record<string, unknown>): string {
|
||||
return period ? `за ${period}` : "за все доступное проверенное окно";
|
||||
}
|
||||
|
||||
function businessOverviewPeriodPhrase(value: string | null | undefined): string {
|
||||
const normalized = toNonEmptyString(value);
|
||||
if (!normalized) {
|
||||
return "за все доступное проверенное окно";
|
||||
}
|
||||
return /^за\s+/iu.test(normalized) ? normalized : `за ${normalized}`;
|
||||
}
|
||||
|
||||
function strongestIncomingYear(overview: Record<string, unknown>): Record<string, unknown> | null {
|
||||
const years = Array.isArray(overview.yearly_breakdown) ? overview.yearly_breakdown : [];
|
||||
const sorted = years
|
||||
@@ -1031,6 +1049,7 @@ function buildCompactBusinessOverviewReply(
|
||||
const compactCashflowRequested = directMoneyOnlyAnswer && requestsCompactCashflowAnswer(turnMeaning, graph);
|
||||
const cashflowPolarityRequested = compactCashflowRequested && requestsCashflowPolarityAnswer(turnMeaning, graph);
|
||||
const directAccountingProfitRequested = requestsDirectAccountingProfitAnswer(turnMeaning, graph);
|
||||
const nextChecksRequested = requestsBusinessOverviewNextChecks(turnMeaning, graph);
|
||||
const rawMessage = toNonEmptyString(turnMeaning?.raw_message) ?? toNonEmptyString(turnMeaning?.effective_message);
|
||||
const earningsAmountRequested = /(?:\u0437\u0430\u0440\u0430\u0431\u043e\u0442|\u0434\u043e\u0445\u043e\u0434\p{L}*)/iu.test(
|
||||
normalizeQuestionText(rawMessage ?? "")
|
||||
@@ -1268,10 +1287,13 @@ function buildCompactBusinessOverviewReply(
|
||||
? `${vendorProcurementQuality.top_non_financial_supplier_share_pct}%`
|
||||
: null;
|
||||
const periodScope = toNonEmptyString(vendorProcurementQuality.period_scope) ?? period;
|
||||
const totalText = totalOutgoing ? `; всего исходящих платежей в проверенном срезе ${totalOutgoing}` : "";
|
||||
const periodPhrase = businessOverviewPeriodPhrase(periodScope);
|
||||
const totalText = totalOutgoing
|
||||
? `; всего исходящих платежей в проверенном срезе ${sentenceAmount(totalOutgoing)}`
|
||||
: "";
|
||||
if (status === "financial_institution_leads_outgoing_cash") {
|
||||
lines.push(
|
||||
`Коротко: проверка концентрации закупок/исходящих платежей за ${periodScope} не подтверждает зависимость от обычного поставщика: крупнейший получатель исходящих денег ${topOutgoingName ?? "не распознан"}${topOutgoingShare ? ` держит около ${topOutgoingShare}` : ""}${topOutgoingAmount ? ` (${topOutgoingAmount})` : ""}, но по названию это банк/финансовая организация${totalText}.`
|
||||
`Коротко: проверка концентрации закупок/исходящих платежей ${periodPhrase} не подтверждает зависимость от обычного поставщика: крупнейший получатель исходящих денег ${topOutgoingName ?? "не распознан"}${topOutgoingShare ? ` держит около ${topOutgoingShare}` : ""}${topOutgoingAmount ? ` (${topOutgoingAmount})` : ""}, но по названию это банк/финансовая организация${totalText}.`
|
||||
);
|
||||
const financialHintText = financialFlowHintTextRuFromRecord(topOutgoingRecord);
|
||||
if (financialHintText) {
|
||||
@@ -1284,11 +1306,11 @@ function buildCompactBusinessOverviewReply(
|
||||
}
|
||||
} else if (status === "reviewed_procurement_concentration") {
|
||||
lines.push(
|
||||
`Коротко: точный риск зависимости от одного поставщика не подтвержден полностью; проверка концентрации закупок/исходящих платежей за ${periodScope} нашла крупнейшего получателя исходящего потока: ${topOutgoingName ?? nonFinancialName ?? "получатель не распознан"}${topOutgoingShare ? ` держит около ${topOutgoingShare}` : nonFinancialShare ? ` держит около ${nonFinancialShare}` : ""}${topOutgoingAmount ? ` (${topOutgoingAmount})` : nonFinancialAmount ? ` (${nonFinancialAmount})` : ""}${totalText}.`
|
||||
`Коротко: точный риск зависимости от одного поставщика не подтвержден полностью; проверка концентрации закупок/исходящих платежей ${periodPhrase} нашла крупнейшего получателя исходящего потока: ${topOutgoingName ?? nonFinancialName ?? "получатель не распознан"}${topOutgoingShare ? ` держит около ${topOutgoingShare}` : nonFinancialShare ? ` держит около ${nonFinancialShare}` : ""}${topOutgoingAmount ? ` (${topOutgoingAmount})` : nonFinancialAmount ? ` (${nonFinancialAmount})` : ""}${totalText}.`
|
||||
);
|
||||
} else {
|
||||
lines.push(
|
||||
`Коротко: проверка концентрации закупок/исходящих платежей за ${periodScope} выполнена, но надежной небанковской концентрации поставщика по найденным исходящим платежам не хватает${totalText}.`
|
||||
`Коротко: проверка концентрации закупок/исходящих платежей ${periodPhrase} выполнена, но надежной небанковской концентрации поставщика по найденным исходящим платежам не хватает${totalText}.`
|
||||
);
|
||||
}
|
||||
const contractText =
|
||||
@@ -1298,7 +1320,7 @@ function buildCompactBusinessOverviewReply(
|
||||
: ` Договорный профиль: используется ${vendorProcurementQuality.used_contracts} договоров.`
|
||||
: "";
|
||||
lines.push(
|
||||
`Что не доказано этим срезом: надежность поставщика, качество поставок, договорные условия, назначение каждого платежа и полная структура всех расходов.${contractText}`
|
||||
`Это не аудит поставщиков: срез не доказывает надежность поставщика, качество поставок, договорные условия, назначение каждого платежа и полную структуру всех расходов.${contractText}`
|
||||
);
|
||||
return joinBusinessReplyLines(lines);
|
||||
}
|
||||
@@ -1352,6 +1374,26 @@ function buildCompactBusinessOverviewReply(
|
||||
return joinBusinessReplyLines(lines);
|
||||
}
|
||||
|
||||
if (
|
||||
!separateSubject &&
|
||||
!crossScopeExecutiveSummary &&
|
||||
!counterpartyLeaderSurfaceRequested &&
|
||||
!rankingNeed &&
|
||||
nextChecksRequested
|
||||
) {
|
||||
const subject = organizationScope ? `по компании ${organizationScope}` : "по компании";
|
||||
lines.push(
|
||||
`В первую очередь ${subject} надо проверить чистую прибыль через закрытие 90/91/99, зависимость от топ-3 клиентов и поставщиков, долги/зависшие расчеты, складские остатки и НДС-позицию.`
|
||||
);
|
||||
lines.push(
|
||||
"Смысл порядка: сначала отделить бухгалтерский финрезультат от денежного нетто, затем проверить концентрацию потоков и только после этого углубляться в склад, долги и налоговую позицию."
|
||||
);
|
||||
if (limitLine) {
|
||||
lines.push(limitLine);
|
||||
}
|
||||
return joinBusinessReplyLines(lines);
|
||||
}
|
||||
|
||||
if (
|
||||
!separateSubject &&
|
||||
!crossScopeExecutiveSummary &&
|
||||
|
||||
@@ -903,6 +903,22 @@ function hasDebtDueDateBoundaryFollowupSignal(text: string): boolean {
|
||||
return hasDueDateCue && hasFollowupShape;
|
||||
}
|
||||
|
||||
function hasSupplierDependencyFollowupSignal(text: string): boolean {
|
||||
if (!text) {
|
||||
return false;
|
||||
}
|
||||
const normalized = compactLower(text);
|
||||
const hasSupplierOrOutgoingCue =
|
||||
/(?:\u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a|\u0437\u0430\u043a\u0443\u043f|\u0438\u0441\u0445\u043e\u0434\u044f\u0449|\u043f\u043b\u0430\u0442[\u0435\u0451]\u0436|\u0437\u0430\u043f\u043b\u0430\u0442|supplier|vendor|procurement|outgoing|payout)/iu.test(
|
||||
normalized
|
||||
);
|
||||
const hasDependencyCue =
|
||||
/(?:\u0437\u0430\u0432\u0438\u0441\u0438\u043c|\u0437\u0430\u0432\u044f\u0437\u0430\u043d|\u043a\u043e\u043d\u0446\u0435\u043d\u0442\u0440\u0430\u0446|\u043a\u043b\u044e\u0447\u0435\u0432|\u043e\u0441\u043d\u043e\u0432\u043d|\u043a\u0440\u0438\u0442\u0438\u0447|dependency|concentration|key|critical)/iu.test(
|
||||
normalized
|
||||
);
|
||||
return hasSupplierOrOutgoingCue && hasDependencyCue;
|
||||
}
|
||||
|
||||
function hasOrganizationLevelDebtDueDateOverviewSignal(text: string): boolean {
|
||||
if (!text) {
|
||||
return false;
|
||||
@@ -1082,7 +1098,7 @@ function hasBusinessOverviewContinuationSignal(text: string): boolean {
|
||||
normalized
|
||||
);
|
||||
const hasAnalystContinuationCue =
|
||||
/(?:можно\s+ли|если\s+нет|proxy|прокси|аудит|оцен|что\s+думаешь|нормальн\p{L}*\s+прибыл|прибыл|марж|рентаб|ликвидн|просроч|качество\s+долг|риск|налогов\p{L}*\s+вывод)/iu.test(
|
||||
/(?:можно\s+ли|если\s+нет|proxy|прокси|аудит|оцен|что\s+думаешь|нормальн\p{L}*\s+прибыл|прибыл|марж|рентаб|ликвидн|просроч|качество\s+долг|риск|зависим|завязан|концентрац|налогов\p{L}*\s+вывод)/iu.test(
|
||||
normalized
|
||||
);
|
||||
const hasTaxContinuationCue =
|
||||
@@ -1868,7 +1884,9 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||
hasOrganizationLevelDebtDueDateOverviewSignal(rawText)) ||
|
||||
debtDueDateFollowupBusinessOverviewSignal;
|
||||
const supplierQualityBusinessOverviewSignal =
|
||||
(rawBusinessOverviewSignal || seededBusinessOverviewSignal) && hasOrganizationLevelSupplierQualityOverviewSignal(rawText);
|
||||
((rawBusinessOverviewSignal || seededBusinessOverviewSignal) &&
|
||||
(hasOrganizationLevelSupplierQualityOverviewSignal(rawText) || hasSupplierDependencyFollowupSignal(rawText))) ||
|
||||
(businessOverviewContinuationSignal && hasSupplierDependencyFollowupSignal(rawText));
|
||||
const profitMarginFollowupBusinessOverviewSignal =
|
||||
businessOverviewContinuationSignal && hasProfitMarginBoundaryFollowupSignal(rawText);
|
||||
const profitMarginBusinessOverviewSignal =
|
||||
@@ -3086,6 +3104,9 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||
if (debtDueDateFollowupBusinessOverviewSignal) {
|
||||
pushReason(reasonCodes, "mcp_discovery_business_overview_debt_due_date_followup_boundary");
|
||||
}
|
||||
if (supplierQualityBusinessOverviewSignal && hasSupplierDependencyFollowupSignal(rawText)) {
|
||||
pushReason(reasonCodes, "mcp_discovery_business_overview_supplier_dependency_followup_boundary");
|
||||
}
|
||||
if (explicitVatSuppressesBusinessOverviewContinuation) {
|
||||
pushReason(reasonCodes, "mcp_discovery_business_overview_continuation_suppressed_by_explicit_vat_question");
|
||||
}
|
||||
|
||||
@@ -426,6 +426,25 @@ function detectBroadBusinessEvaluation(text) {
|
||||
family: "broad_business_evaluation"
|
||||
};
|
||||
}
|
||||
if (
|
||||
/(?:что\s+(?:дальше\s+)?провер\w*|что\s+провер\w*\s+дальше|следующ\w*\s+шаг|в\s+первую\s+очередь\s+провер\w*|next\s+checks?|next\s+steps?)/iu.test(
|
||||
normalized
|
||||
)
|
||||
) {
|
||||
return {
|
||||
family: "broad_business_evaluation"
|
||||
};
|
||||
}
|
||||
if (
|
||||
/(?:поставщик|закуп|исходящ|плат[её]ж|supplier|vendor|procurement|outgoing|payout)/iu.test(normalized) &&
|
||||
/(?:зависим|завязан|концентрац|ключев|основн|критич|dependency|concentration|key|critical)/iu.test(
|
||||
normalized
|
||||
)
|
||||
) {
|
||||
return {
|
||||
family: "broad_business_evaluation"
|
||||
};
|
||||
}
|
||||
if (hasOrganizationLevelEarningsOverviewSignal(normalized)) {
|
||||
return {
|
||||
family: "broad_business_evaluation"
|
||||
|
||||
Reference in New Issue
Block a user