ДОМЕНЫ - ВОПРОСЫ - Этап 4: точный маршрут confirmed payables на дату без эвристического фолбэка
This commit is contained in:
@@ -419,6 +419,7 @@ function shouldAttemptCounterpartyCatalogResolution(intent: AddressIntent, filte
|
||||
intent === "bank_operations_by_counterparty" ||
|
||||
intent === "open_items_by_counterparty_or_contract" ||
|
||||
intent === "list_payables_counterparties" ||
|
||||
intent === "payables_confirmed_as_of_date" ||
|
||||
intent === "list_receivables_counterparties"
|
||||
);
|
||||
}
|
||||
@@ -745,6 +746,7 @@ function isCounterpartyRiskIntent(intent: AddressIntent): boolean {
|
||||
return (
|
||||
intent === "list_receivables_counterparties" ||
|
||||
intent === "list_payables_counterparties" ||
|
||||
intent === "payables_confirmed_as_of_date" ||
|
||||
intent === "list_open_contracts" ||
|
||||
intent === "open_items_by_counterparty_or_contract"
|
||||
);
|
||||
@@ -760,7 +762,11 @@ function isHeuristicCandidatesIntent(intent: AddressIntent): boolean {
|
||||
}
|
||||
|
||||
function isConfirmedBalanceIntent(intent: AddressIntent): boolean {
|
||||
return intent === "account_balance_snapshot" || intent === "documents_forming_balance";
|
||||
return (
|
||||
intent === "account_balance_snapshot" ||
|
||||
intent === "documents_forming_balance" ||
|
||||
intent === "payables_confirmed_as_of_date"
|
||||
);
|
||||
}
|
||||
|
||||
function resolveAsOfDateBasis(filters: AddressFilterSet): AddressAsOfDateBasis | null {
|
||||
@@ -845,11 +851,12 @@ function deriveAddressResultSemantics(input: {
|
||||
};
|
||||
}
|
||||
if (isConfirmedBalanceIntent(input.intent)) {
|
||||
const balanceConfirmed = input.responseType !== "LIMITED_WITH_REASON";
|
||||
return {
|
||||
requested_result_mode: requestedResultMode,
|
||||
result_mode: "confirmed_balance",
|
||||
evidence_strength: deriveAddressEvidenceStrength(input),
|
||||
balance_confirmed: true,
|
||||
balance_confirmed: balanceConfirmed,
|
||||
as_of_date_basis: asOfDateBasis ?? "period_end"
|
||||
};
|
||||
}
|
||||
@@ -1463,6 +1470,8 @@ function buildLimitedOffers(input: {
|
||||
|
||||
if (input.intent === "list_receivables_counterparties") {
|
||||
offers.push("показать контрагентов с максимальными хвостами дебиторки по 62/76");
|
||||
} else if (input.intent === "payables_confirmed_as_of_date") {
|
||||
offers.push("показать подтвержденный реестр открытых обязательств на дату среза по 60/76");
|
||||
} else if (input.intent === "list_payables_counterparties") {
|
||||
offers.push("показать контрагентов с максимальными хвостами кредиторки по 60/76");
|
||||
} else if (input.intent === "open_items_by_counterparty_or_contract" || input.intent === "list_open_contracts") {
|
||||
@@ -1512,7 +1521,8 @@ function buildLimitedIntentSignalLine(input: {
|
||||
open_items_by_counterparty_or_contract: "Сигнал запроса: нужен контроль незакрытых взаиморасчетов.",
|
||||
list_open_contracts: "Сигнал запроса: нужен список незакрытых договоров на дату.",
|
||||
list_receivables_counterparties: "Сигнал запроса: нужен ранжированный список должников.",
|
||||
list_payables_counterparties: "Сигнал запроса: нужен ранжированный список кредиторов."
|
||||
list_payables_counterparties: "Сигнал запроса: нужен ранжированный список кредиторов.",
|
||||
payables_confirmed_as_of_date: "Сигнал запроса: нужен подтвержденный срез обязательств к оплате на дату."
|
||||
};
|
||||
|
||||
const byShape: Partial<Record<AddressQueryShapeDetection["shape"], string>> = {
|
||||
@@ -1655,7 +1665,7 @@ function composeLimitedReply(input: {
|
||||
lines.push(`Что могу сделать сейчас: ${offers.join("; ")}.`);
|
||||
}
|
||||
|
||||
return lines.join("\n");
|
||||
return lines.join("\n\n");
|
||||
}
|
||||
|
||||
function buildLimitedExecutionResult(input: {
|
||||
@@ -1701,12 +1711,17 @@ function buildLimitedExecutionResult(input: {
|
||||
rowsMatched: input.rowsMatched
|
||||
});
|
||||
const requestedResultMode = resolveRequestedResultMode(input.intent.intent, input.filters);
|
||||
const reasons = withConfirmedBalanceFallbackReason(
|
||||
const reasonsWithConfirmedFallback = withConfirmedBalanceFallbackReason(
|
||||
input.reasons,
|
||||
requestedResultMode,
|
||||
undefined,
|
||||
resultSemantics.result_mode
|
||||
);
|
||||
const reasons =
|
||||
input.intent.intent === "payables_confirmed_as_of_date" &&
|
||||
!reasonsWithConfirmedFallback.includes("exact_payables_mode_limited_response")
|
||||
? [...reasonsWithConfirmedFallback, "exact_payables_mode_limited_response"]
|
||||
: reasonsWithConfirmedFallback;
|
||||
return {
|
||||
handled: true,
|
||||
reply_text: composeLimitedReply({
|
||||
@@ -1795,7 +1810,8 @@ export class AddressQueryService {
|
||||
}
|
||||
const requestedResultMode = resolveRequestedResultMode(intent.intent, filters.extracted_filters);
|
||||
const payablesConfirmedExecution =
|
||||
intent.intent === "list_payables_counterparties" && requestedResultMode === "confirmed_balance"
|
||||
(intent.intent === "list_payables_counterparties" || intent.intent === "payables_confirmed_as_of_date") &&
|
||||
requestedResultMode === "confirmed_balance"
|
||||
? resolveExecutionFiltersForPayablesConfirmedBalance(filters.extracted_filters, analysisDate)
|
||||
: null;
|
||||
const executionFilters = payablesConfirmedExecution?.executionFilters ?? filters.extracted_filters;
|
||||
@@ -1846,6 +1862,9 @@ export class AddressQueryService {
|
||||
if (preferConfirmedBalanceForPayablesLifecycle && !baseReasons.includes("confirmed_balance_attempt_for_payables_debt_lifecycle")) {
|
||||
baseReasons.push("confirmed_balance_attempt_for_payables_debt_lifecycle");
|
||||
}
|
||||
if (intent.intent === "payables_confirmed_as_of_date" && !baseReasons.includes("confirmed_balance_exact_payables_intent")) {
|
||||
baseReasons.push("confirmed_balance_exact_payables_intent");
|
||||
}
|
||||
if (
|
||||
requestedResultMode === "confirmed_balance" &&
|
||||
recipeIntent === "open_items_by_counterparty_or_contract" &&
|
||||
@@ -1982,11 +2001,13 @@ export class AddressQueryService {
|
||||
query: plan.query,
|
||||
limit: plan.limit
|
||||
});
|
||||
const allowOpenItemsFallbackForMissingSubconto = intent.intent !== "payables_confirmed_as_of_date";
|
||||
if (
|
||||
mcp.error &&
|
||||
(plan.recipe.recipe_id === "address_movements_receivables_v1" ||
|
||||
plan.recipe.recipe_id === "address_movements_payables_v1") &&
|
||||
isMissingSubcontoFieldError(mcp.error)
|
||||
isMissingSubcontoFieldError(mcp.error) &&
|
||||
allowOpenItemsFallbackForMissingSubconto
|
||||
) {
|
||||
const fallbackSelection = selectAddressRecipe("open_items_by_counterparty_or_contract", executionFilters);
|
||||
if (fallbackSelection.selected_recipe && fallbackSelection.missing_required_filters.length === 0) {
|
||||
@@ -2019,11 +2040,21 @@ export class AddressQueryService {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!baseReasons.includes("mcp_missing_subconto_field_auto_fallback_unavailable")) {
|
||||
baseReasons.push("mcp_missing_subconto_field_auto_fallback_unavailable");
|
||||
}
|
||||
if (!baseReasons.includes("mcp_missing_subconto_field_auto_fallback_unavailable")) {
|
||||
baseReasons.push("mcp_missing_subconto_field_auto_fallback_unavailable");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
mcp.error &&
|
||||
(plan.recipe.recipe_id === "address_movements_receivables_v1" ||
|
||||
plan.recipe.recipe_id === "address_movements_payables_v1") &&
|
||||
isMissingSubcontoFieldError(mcp.error) &&
|
||||
!allowOpenItemsFallbackForMissingSubconto &&
|
||||
!baseReasons.includes("confirmed_payables_exact_mode_missing_subconto_no_heuristic_fallback")
|
||||
) {
|
||||
baseReasons.push("confirmed_payables_exact_mode_missing_subconto_no_heuristic_fallback");
|
||||
}
|
||||
|
||||
if (mcp.error) {
|
||||
const errorScopeAudit = buildDefaultAccountScopeAudit(filters.extracted_filters);
|
||||
@@ -2846,6 +2877,36 @@ export class AddressQueryService {
|
||||
}),
|
||||
factual.semantics
|
||||
);
|
||||
if (intent.intent === "payables_confirmed_as_of_date" && factualResultSemantics.balance_confirmed !== true) {
|
||||
return buildLimitedExecutionResult({
|
||||
mode,
|
||||
shape,
|
||||
intent,
|
||||
filters: filters.extracted_filters,
|
||||
missingRequiredFilters: [],
|
||||
selectedRecipe: effectiveRecipeId,
|
||||
accountScopeMode: plan.account_scope_mode,
|
||||
accountScopeFallbackApplied,
|
||||
accountScopeAudit,
|
||||
anchor,
|
||||
matchFailureStage,
|
||||
matchFailureReason,
|
||||
mcpCallStatus: stageStatus,
|
||||
rowsFetched: mcp.fetched_rows,
|
||||
rawRowsReceived: mcp.raw_rows.length,
|
||||
rowsAfterAccountScope: normalizedRows.length,
|
||||
rowsAfterRecipeFilter: filterByAnchors.length,
|
||||
rowsMaterialized: normalizedRows.length,
|
||||
rowsMatched: filteredRows.length,
|
||||
rawRowKeysSample: rowDiagnostics.rawRowKeysSample,
|
||||
materializationDropReason: rowDiagnostics.materializationDropReason,
|
||||
category: "recipe_visibility_gap",
|
||||
reasonText: "exact payables mode: confirmed balance was not proven for the requested as-of slice",
|
||||
nextStep: "specify as_of_date/counterparty or enable detailed settlement registers for exact confirmed balance",
|
||||
limitations: ["exact_payables_mode_unconfirmed_output_blocked"],
|
||||
reasons: [...baseReasons, "exact_payables_mode_unconfirmed_output_blocked"]
|
||||
});
|
||||
}
|
||||
return {
|
||||
handled: true,
|
||||
reply_text: factual.text,
|
||||
|
||||
Reference in New Issue
Block a user