Архитектура: ввести answer-inspection follow-up contract и закрыть phase15 replay
This commit is contained in:
@@ -75,6 +75,36 @@ function buildAddressMemoryRecapReply(input) {
|
||||
}
|
||||
return "Да, помню предыдущий адресный контур. Могу кратко напомнить, что мы уже подтвердили, или сразу продолжить следующий шаг.";
|
||||
}
|
||||
function buildSelectedObjectAnswerInspectionReply(input) {
|
||||
const extractedFilters = input.addressDebug?.extracted_filters && typeof input.addressDebug.extracted_filters === "object"
|
||||
? input.addressDebug.extracted_filters
|
||||
: null;
|
||||
const item = input.toNonEmptyString(extractedFilters?.item) ??
|
||||
(String(input.addressDebug?.anchor_type ?? "") === "item"
|
||||
? input.toNonEmptyString(input.addressDebug?.anchor_value_resolved) ??
|
||||
input.toNonEmptyString(input.addressDebug?.anchor_value_raw)
|
||||
: null);
|
||||
const detectedIntent = String(input.addressDebug?.detected_intent ?? "");
|
||||
const itemLabel = item ?? "эта позиция";
|
||||
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(" ");
|
||||
}
|
||||
async function runAssistantLivingChatRuntime(input) {
|
||||
const userMessage = String(input.userMessage ?? "");
|
||||
const organizationAuthority = (0, assistantContinuityPolicy_1.resolveAssistantOrganizationAuthority)({
|
||||
@@ -114,6 +144,7 @@ async function runAssistantLivingChatRuntime(input) {
|
||||
const contextualMemoryRecapFollowup = memoryRecapContext.contextualMemoryRecapFollowup;
|
||||
const lastGroundedInventoryAddressDebug = memoryRecapContext.lastGroundedInventoryAddressDebug;
|
||||
const lastMemoryAddressDebug = memoryRecapContext.lastMemoryAddressDebug;
|
||||
const contextualAnswerInspectionFollowup = String(input.modeDecision?.reason ?? "") === "answer_inspection_followup_detected";
|
||||
if (capabilityMetaQuery && (destructiveSignal || dangerSignal)) {
|
||||
chatText = input.buildAssistantSafetyRefusalReply();
|
||||
livingChatSource = "deterministic_safety_refusal";
|
||||
@@ -178,6 +209,13 @@ async function runAssistantLivingChatRuntime(input) {
|
||||
activeOrganization = scopedOrganization ?? activeOrganization;
|
||||
livingChatSource = "deterministic_memory_recap_contract";
|
||||
}
|
||||
else if (contextualAnswerInspectionFollowup) {
|
||||
chatText = buildSelectedObjectAnswerInspectionReply({
|
||||
addressDebug: continuitySnapshot.lastGroundedItemAddressDebug ?? continuitySnapshot.lastGroundedAddressDebug,
|
||||
toNonEmptyString: input.toNonEmptyString
|
||||
});
|
||||
livingChatSource = "deterministic_answer_inspection_contract";
|
||||
}
|
||||
else if (capabilityMetaQuery) {
|
||||
chatText = input.buildAssistantCapabilityContractReply(userMessage);
|
||||
livingChatSource = "deterministic_capability_contract";
|
||||
|
||||
@@ -96,6 +96,29 @@ function createAssistantLivingModePolicy(deps) {
|
||||
hasDataRetrievalRequestSignal(sample) ||
|
||||
hasStrongDataIntentSignal(sample));
|
||||
}
|
||||
function hasAnswerInspectionFollowupSignal(userMessage) {
|
||||
const rawText = compactWhitespace(String(userMessage ?? "").toLowerCase());
|
||||
const repairedText = compactWhitespace(repairAddressMojibake(String(userMessage ?? "")).toLowerCase());
|
||||
const samples = [rawText, repairedText]
|
||||
.filter((item) => item.length > 0)
|
||||
.map((item) => item.replace(/ё/g, "е"));
|
||||
if (samples.length === 0) {
|
||||
return false;
|
||||
}
|
||||
const hasInspectionCue = samples.some((sample) => /(?:ошибк|неверн|не так|перепутал|у тебя написано|ты написал|это ошибка|правильно ли|корректн)/iu.test(sample));
|
||||
if (!hasInspectionCue) {
|
||||
return false;
|
||||
}
|
||||
const hasAnswerObjectCue = samples.some((sample) => /(?:контрагент|покупател|поставщик|поле|ответ|позици|номенклат|документ)/iu.test(sample));
|
||||
if (!hasAnswerObjectCue) {
|
||||
return false;
|
||||
}
|
||||
const hasFreshRetrievalAction = samples.some((sample) => /(?:покажи|выведи|найди|список|проверь по базе|подними документы|достань|рассчитай|посчитай|сколько|кто\s+нам|кто\s+у\s+нас)/iu.test(sample));
|
||||
if (hasFreshRetrievalAction) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function hasConversationMemoryRecallFollowupSignal(userMessage) {
|
||||
const rawText = compactWhitespace(String(userMessage ?? "").toLowerCase());
|
||||
const repairedText = compactWhitespace(repairAddressMojibake(String(userMessage ?? "")).toLowerCase());
|
||||
@@ -348,6 +371,7 @@ function createAssistantLivingModePolicy(deps) {
|
||||
hasDataRetrievalRequestSignal,
|
||||
hasOrganizationFactLookupSignal,
|
||||
hasMetaAnswerFollowupSignal,
|
||||
hasAnswerInspectionFollowupSignal,
|
||||
hasConversationMemoryRecallFollowupSignal,
|
||||
hasHistoricalCapabilityFollowupSignal,
|
||||
hasOrganizationFactFollowupSignal,
|
||||
|
||||
@@ -27,14 +27,16 @@ function createAssistantMetaFollowupPolicy(deps) {
|
||||
return {
|
||||
dataScopeMetaQuery: false,
|
||||
capabilityMetaQuery: false,
|
||||
metaAnswerFollowupSignal: false
|
||||
metaAnswerFollowupSignal: false,
|
||||
answerInspectionFollowupSignal: false
|
||||
};
|
||||
}
|
||||
return {
|
||||
dataScopeMetaQuery: hasSignalAcrossSamples(samples, deps.hasAssistantDataScopeMetaQuestionSignal),
|
||||
capabilityMetaQuery: hasSignalAcrossSamples(samples, deps.shouldHandleAsAssistantCapabilityMetaQuery) ||
|
||||
hasImplicitHistoricalCapabilityMetaSignal(samples),
|
||||
metaAnswerFollowupSignal: hasSignalAcrossSamples(samples, deps.hasMetaAnswerFollowupSignal)
|
||||
metaAnswerFollowupSignal: hasSignalAcrossSamples(samples, deps.hasMetaAnswerFollowupSignal),
|
||||
answerInspectionFollowupSignal: hasSignalAcrossSamples(samples, deps.hasAnswerInspectionFollowupSignal)
|
||||
};
|
||||
}
|
||||
function resolveHardMetaMode(input) {
|
||||
@@ -60,9 +62,18 @@ function createAssistantMetaFollowupPolicy(deps) {
|
||||
(!input.llmContractIntent || String(input.llmContractIntent) === "unknown") &&
|
||||
String(input.llmContractMode ?? "") !== "address_query");
|
||||
}
|
||||
function isAnswerInspectionFollowupOverGroundedAnswer(input) {
|
||||
return Boolean(input.followupContext &&
|
||||
input.hasPriorAddressAnswerContext &&
|
||||
input.answerInspectionFollowupSignal &&
|
||||
!input.dataScopeMetaQuery &&
|
||||
!input.capabilityMetaQuery &&
|
||||
!input.aggregateBusinessAnalyticsSignal);
|
||||
}
|
||||
return {
|
||||
resolveMetaSignalSet,
|
||||
resolveHardMetaMode,
|
||||
isMetaFollowupOverGroundedAnswer
|
||||
isMetaFollowupOverGroundedAnswer,
|
||||
isAnswerInspectionFollowupOverGroundedAnswer
|
||||
};
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ function shouldBypassStrictDeepInvestigationCueForAddressIntent(intent) {
|
||||
return Boolean(intent && ADDRESS_INTENTS_ALLOW_STRICT_DEEP_INVESTIGATION_BYPASS.has(intent));
|
||||
}
|
||||
function createAssistantRoutePolicy(deps) {
|
||||
const { repairAddressMojibake, findLastGroundedAddressAnswerDebug, findLastOrganizationClarificationAddressDebug, mergeKnownOrganizations, normalizeOrganizationScopeValue, resolveOrganizationSelectionFromMessage, resolveMetaSignalSet, resolveHardMetaMode, isMetaFollowupOverGroundedAnswer, hasDataRetrievalRequestSignal, hasOrganizationFactLookupSignal, hasOrganizationFactFollowupSignal, hasAggregateBusinessAnalyticsSignal, hasStandaloneAddressTopicSignal, hasOpenContractsAddressSignal, detectAddressQuestionMode, resolveAddressIntent, toNonEmptyString, hasStrictDeepInvestigationCue, hasStrongDataIntentSignal, hasAccountingSignal, hasDangerOrCoercionSignal, hasAddressFollowupContextSignal, hasShortDebtMirrorFollowupSignal, isInventorySelectedObjectIntent, hasShortInventoryObjectFollowupSignal, isGroundedInventoryContextDebug, resolveRouteMemorySignals, findLastAddressAssistantItem, resolveAddressToolGateDecision, hasSameDateAccountFollowupSignalForPredecompose, hasLooseAllTimeAddressLookupSignal, hasDeepAnalysisPreferenceSignal, hasDirectDeepAnalysisSignal, compactWhitespace, hasDeepSessionContinuationSignal, resolveLivingAssistantModeDecision, resolveProviderExecutionState } = deps;
|
||||
const { repairAddressMojibake, findLastGroundedAddressAnswerDebug, findLastOrganizationClarificationAddressDebug, mergeKnownOrganizations, normalizeOrganizationScopeValue, resolveOrganizationSelectionFromMessage, resolveMetaSignalSet, resolveHardMetaMode, isMetaFollowupOverGroundedAnswer, isAnswerInspectionFollowupOverGroundedAnswer, hasDataRetrievalRequestSignal, hasOrganizationFactLookupSignal, hasOrganizationFactFollowupSignal, hasAggregateBusinessAnalyticsSignal, hasStandaloneAddressTopicSignal, hasOpenContractsAddressSignal, detectAddressQuestionMode, resolveAddressIntent, toNonEmptyString, hasStrictDeepInvestigationCue, hasStrongDataIntentSignal, hasAccountingSignal, hasDangerOrCoercionSignal, hasAddressFollowupContextSignal, hasShortDebtMirrorFollowupSignal, isInventorySelectedObjectIntent, hasShortInventoryObjectFollowupSignal, isGroundedInventoryContextDebug, resolveRouteMemorySignals, findLastAddressAssistantItem, resolveAddressToolGateDecision, hasSameDateAccountFollowupSignalForPredecompose, hasLooseAllTimeAddressLookupSignal, hasDeepAnalysisPreferenceSignal, hasDirectDeepAnalysisSignal, compactWhitespace, hasDeepSessionContinuationSignal, resolveLivingAssistantModeDecision, resolveProviderExecutionState } = deps;
|
||||
function hasInventoryRootRestatementFollowupSignal(text) {
|
||||
const normalized = compactWhitespace(repairAddressMojibake(String(text ?? "")).toLowerCase()).replace(/ё/g, "е");
|
||||
if (!normalized) {
|
||||
@@ -580,6 +580,7 @@ function createAssistantRoutePolicy(deps) {
|
||||
};
|
||||
}
|
||||
const metaAnswerFollowupSignal = metaSignals.metaAnswerFollowupSignal;
|
||||
const answerInspectionFollowupSignal = metaSignals.answerInspectionFollowupSignal;
|
||||
const preserveAddressLaneSignal = Boolean((llmPreDecomposeMeta?.llmCanonicalCandidateDetected &&
|
||||
llmPreDecomposeMeta?.applied &&
|
||||
llmContractMode === "address_query") ||
|
||||
@@ -707,6 +708,23 @@ function createAssistantRoutePolicy(deps) {
|
||||
followupContext,
|
||||
hasPriorAddressAnswerContext,
|
||||
metaAnswerFollowupSignal,
|
||||
answerInspectionFollowupSignal,
|
||||
vatEvaluativeFollowupSignal,
|
||||
dataScopeMetaQuery,
|
||||
capabilityMetaQuery,
|
||||
aggregateBusinessAnalyticsSignal,
|
||||
dataRetrievalSignal,
|
||||
strongDataSignal,
|
||||
resolvedMode: resolvedModeDetection.mode,
|
||||
resolvedIntent: resolvedIntentResolution.intent,
|
||||
llmContractIntent,
|
||||
llmContractMode
|
||||
});
|
||||
const answerInspectionFollowupOverGroundedAnswer = isAnswerInspectionFollowupOverGroundedAnswer({
|
||||
followupContext,
|
||||
hasPriorAddressAnswerContext,
|
||||
metaAnswerFollowupSignal,
|
||||
answerInspectionFollowupSignal,
|
||||
vatEvaluativeFollowupSignal,
|
||||
dataScopeMetaQuery,
|
||||
capabilityMetaQuery,
|
||||
@@ -762,6 +780,11 @@ function createAssistantRoutePolicy(deps) {
|
||||
toolGateDecision = "skip_address_lane";
|
||||
toolGateReason = "meta_followup_over_grounded_answer";
|
||||
}
|
||||
if (answerInspectionFollowupOverGroundedAnswer) {
|
||||
runAddressLane = false;
|
||||
toolGateDecision = "skip_address_lane";
|
||||
toolGateReason = "answer_inspection_followup_over_grounded_answer";
|
||||
}
|
||||
let livingDecision = resolveLivingAssistantModeDecision({
|
||||
userMessage: rawUserMessage,
|
||||
addressLaneTriggered: runAddressLane,
|
||||
@@ -802,6 +825,12 @@ function createAssistantRoutePolicy(deps) {
|
||||
reason: "meta_followup_over_grounded_answer"
|
||||
};
|
||||
}
|
||||
if (answerInspectionFollowupOverGroundedAnswer) {
|
||||
livingDecision = {
|
||||
mode: "chat",
|
||||
reason: "answer_inspection_followup_detected"
|
||||
};
|
||||
}
|
||||
return {
|
||||
runAddressLane,
|
||||
toolGateDecision,
|
||||
@@ -834,6 +863,7 @@ function createAssistantRoutePolicy(deps) {
|
||||
deep_analysis_signal_fallback_to_deep: deepAnalysisSignalFallbackToDeep,
|
||||
aggregate_analytics_signal_fallback_to_deep: aggregateAnalyticsFallbackToDeep,
|
||||
deep_session_continuation_fallback_to_deep: deepSessionContinuationFallbackToDeep,
|
||||
answer_inspection_followup_over_grounded_answer: answerInspectionFollowupOverGroundedAnswer,
|
||||
final_decision: {
|
||||
run_address_lane: runAddressLane,
|
||||
tool_gate_decision: toolGateDecision,
|
||||
|
||||
@@ -4223,7 +4223,8 @@ const assistantLivingModePolicy = (0, assistantLivingModePolicy_1.createAssistan
|
||||
const assistantMetaFollowupPolicy = (0, assistantMetaFollowupPolicy_1.createAssistantMetaFollowupPolicy)({
|
||||
hasAssistantDataScopeMetaQuestionSignal: assistantLivingModePolicy.hasAssistantDataScopeMetaQuestionSignal,
|
||||
shouldHandleAsAssistantCapabilityMetaQuery: assistantLivingModePolicy.shouldHandleAsAssistantCapabilityMetaQuery,
|
||||
hasMetaAnswerFollowupSignal: assistantLivingModePolicy.hasMetaAnswerFollowupSignal
|
||||
hasMetaAnswerFollowupSignal: assistantLivingModePolicy.hasMetaAnswerFollowupSignal,
|
||||
hasAnswerInspectionFollowupSignal: assistantLivingModePolicy.hasAnswerInspectionFollowupSignal
|
||||
});
|
||||
const assistantMemoryRecapPolicy = (0, assistantMemoryRecapPolicy_1.createAssistantMemoryRecapPolicy)({
|
||||
hasHistoricalCapabilityFollowupSignal: assistantLivingModePolicy.hasHistoricalCapabilityFollowupSignal,
|
||||
@@ -4240,6 +4241,7 @@ const assistantRoutePolicy = (0, assistantRoutePolicy_1.createAssistantRoutePoli
|
||||
resolveMetaSignalSet: assistantMetaFollowupPolicy.resolveMetaSignalSet,
|
||||
resolveHardMetaMode: assistantMetaFollowupPolicy.resolveHardMetaMode,
|
||||
isMetaFollowupOverGroundedAnswer: assistantMetaFollowupPolicy.isMetaFollowupOverGroundedAnswer,
|
||||
isAnswerInspectionFollowupOverGroundedAnswer: assistantMetaFollowupPolicy.isAnswerInspectionFollowupOverGroundedAnswer,
|
||||
hasDataRetrievalRequestSignal: assistantLivingModePolicy.hasDataRetrievalRequestSignal,
|
||||
hasOrganizationFactLookupSignal,
|
||||
hasOrganizationFactFollowupSignal: assistantLivingModePolicy.hasOrganizationFactFollowupSignal,
|
||||
|
||||
Reference in New Issue
Block a user