ГЛОБАЛЬНЫЙ РЕФАКТОРИНГ АРХИТЕКТУРЫ - Рефакторинг этапов 2.28 - вынос retry-orchestration адресного лейна (контекстный прогон, primary, retry сырого вопроса, fallback limited) в отдельный адаптер.

This commit is contained in:
2026-04-10 20:21:53 +03:00
parent 9b1d1bff91
commit 3531f7ddfe
9 changed files with 814 additions and 235 deletions
@@ -0,0 +1,115 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.runAssistantAddressLaneRuntime = runAssistantAddressLaneRuntime;
function limitedCategory(addressLane) {
return typeof addressLane?.debug?.limited_reason_category === "string"
? addressLane.debug.limited_reason_category
: null;
}
async function runAssistantAddressLaneRuntime(input) {
const retryAudit = {
attempted: false,
reason: null,
initial_limited_category: null,
retry_message: null,
retry_used_followup_context: false,
retry_result_category: null
};
let pendingLimited = null;
const evaluateAddressLane = (addressLane, messageUsed, carryMeta) => {
if (!addressLane?.handled) {
return { action: "continue" };
}
if (!input.isRetryableAddressLimitedResult(addressLane)) {
return {
action: "return",
selection: {
addressLane,
messageUsed,
carryMeta
}
};
}
if (!pendingLimited) {
pendingLimited = {
addressLane,
messageUsed,
carryMeta
};
}
return { action: "continue" };
};
if (input.shouldPreferContextualLane) {
const contextualAddressLane = await input.runAddressLaneAttempt(input.addressInputMessage, input.carryover);
const decision = evaluateAddressLane(contextualAddressLane, input.addressInputMessage, input.carryover);
if (decision.action === "return") {
return {
handled: true,
selection: decision.selection,
retryAudit
};
}
}
const primaryAddressLane = await input.runAddressLaneAttempt(input.addressInputMessage, null);
const primaryDecision = evaluateAddressLane(primaryAddressLane, input.addressInputMessage, null);
if (primaryDecision.action === "return") {
return {
handled: true,
selection: primaryDecision.selection,
retryAudit
};
}
if (!input.shouldPreferContextualLane && input.carryover?.followupContext) {
const contextualAddressLane = await input.runAddressLaneAttempt(input.addressInputMessage, input.carryover);
const contextualDecision = evaluateAddressLane(contextualAddressLane, input.addressInputMessage, input.carryover);
if (contextualDecision.action === "return") {
return {
handled: true,
selection: contextualDecision.selection,
retryAudit
};
}
}
const pendingLimitedSelection = pendingLimited;
if (pendingLimitedSelection && input.canRetryWithRawUserMessage) {
retryAudit.attempted = true;
retryAudit.reason = "limited_result_retry_with_raw_message";
retryAudit.initial_limited_category = limitedCategory(pendingLimitedSelection?.addressLane ?? null);
retryAudit.retry_message = input.userMessage;
if (input.carryover?.followupContext) {
retryAudit.retry_used_followup_context = true;
const rawContextualLane = await input.runAddressLaneAttempt(input.userMessage, input.carryover);
const rawContextualDecision = evaluateAddressLane(rawContextualLane, input.userMessage, input.carryover);
if (rawContextualDecision.action === "return") {
retryAudit.retry_result_category = limitedCategory(rawContextualDecision.selection.addressLane);
return {
handled: true,
selection: rawContextualDecision.selection,
retryAudit
};
}
}
const rawPrimaryLane = await input.runAddressLaneAttempt(input.userMessage, null);
retryAudit.retry_result_category = limitedCategory(rawPrimaryLane);
const rawPrimaryDecision = evaluateAddressLane(rawPrimaryLane, input.userMessage, null);
if (rawPrimaryDecision.action === "return") {
return {
handled: true,
selection: rawPrimaryDecision.selection,
retryAudit
};
}
}
if (pendingLimited) {
return {
handled: true,
selection: pendingLimited,
retryAudit
};
}
return {
handled: false,
selection: null,
retryAudit
};
}
@@ -0,0 +1,58 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildAssistantAddressOrchestrationRuntime = buildAssistantAddressOrchestrationRuntime;
function fallbackAddressPreDecompose(userMessage, llmProvider, buildAddressLlmPredecomposeContractV1, sanitizeAddressMessageForFallback) {
const provider = llmProvider === "local" ? "local" : llmProvider === "openai" ? "openai" : null;
return {
attempted: false,
applied: false,
provider,
traceId: null,
effectiveMessage: userMessage,
reason: "disabled_by_feature_flag",
llmCanonicalCandidateDetected: false,
predecomposeContract: buildAddressLlmPredecomposeContractV1({
sourceMessage: userMessage,
canonicalMessage: userMessage
}),
fallbackRuleHit: null,
sanitizedUserMessage: sanitizeAddressMessageForFallback(userMessage),
toolGateDecision: null,
toolGateReason: null
};
}
async function buildAssistantAddressOrchestrationRuntime(input) {
const addressPreDecompose = input.featureAddressLlmPredecomposeV1
? await input.runAddressLlmPreDecompose()
: fallbackAddressPreDecompose(input.userMessage, input.llmProvider, input.buildAddressLlmPredecomposeContractV1, input.sanitizeAddressMessageForFallback);
const addressInputMessage = input.toNonEmptyString(addressPreDecompose?.effectiveMessage) ?? input.userMessage;
const carryover = input.resolveAddressFollowupCarryoverContext(input.userMessage, input.sessionItems, addressInputMessage, addressPreDecompose);
const followupContext = carryover?.followupContext ?? null;
const orchestrationDecision = input.resolveAssistantOrchestrationDecision({
rawUserMessage: input.userMessage,
effectiveAddressUserMessage: addressInputMessage,
followupContext,
llmPreDecomposeMeta: addressPreDecompose,
useMock: input.useMock
});
const dialogContinuationContract = input.buildAddressDialogContinuationContractV2(input.userMessage, addressInputMessage, carryover, addressPreDecompose);
const addressRuntimeMeta = {
...addressPreDecompose,
toolGateDecision: orchestrationDecision.toolGateDecision ?? null,
toolGateReason: orchestrationDecision.toolGateReason ?? null,
dialogContinuationContract,
orchestrationContract: orchestrationDecision.orchestrationContract ?? null
};
const livingModeDecision = {
mode: orchestrationDecision.livingMode,
reason: orchestrationDecision.livingReason
};
return {
addressPreDecompose,
addressInputMessage,
carryover,
orchestrationDecision,
addressRuntimeMeta,
livingModeDecision
};
}
+35 -117
View File
@@ -75,6 +75,8 @@ const assistantDeepTurnGroundingRuntimeAdapter_1 = __importStar(require("./assis
const assistantDeepTurnPackagingRuntimeAdapter_1 = __importStar(require("./assistantDeepTurnPackagingRuntimeAdapter"));
const assistantDeepTurnPlanRuntimeAdapter_1 = __importStar(require("./assistantDeepTurnPlanRuntimeAdapter"));
const assistantDeepTurnRetrievalRuntimeAdapter_1 = __importStar(require("./assistantDeepTurnRetrievalRuntimeAdapter"));
const assistantAddressLaneRuntimeAdapter_1 = __importStar(require("./assistantAddressLaneRuntimeAdapter"));
const assistantAddressOrchestrationRuntimeAdapter_1 = __importStar(require("./assistantAddressOrchestrationRuntimeAdapter"));
const assistantLivingChatTurnFinalizeRuntimeAdapter_1 = __importStar(require("./assistantLivingChatTurnFinalizeRuntimeAdapter"));
const assistantLivingChatRuntimeAdapter_1 = __importStar(require("./assistantLivingChatRuntimeAdapter"));
const assistantQueryPlanning_1 = __importStar(require("./assistantQueryPlanning"));
@@ -4560,47 +4562,27 @@ class AssistantService {
};
let addressRuntimeMetaForDeep = null;
if (config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_V1) {
const addressPreDecompose = config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_LLM_PREDECOMPOSE_V1
? await runAddressLlmPreDecompose(this.normalizerService, payload, userMessage)
: {
attempted: false,
applied: false,
provider: payload?.llmProvider === "local" ? "local" : payload?.llmProvider === "openai" ? "openai" : null,
traceId: null,
effectiveMessage: userMessage,
reason: "disabled_by_feature_flag",
llmCanonicalCandidateDetected: false,
predecomposeContract: (0, predecomposeContract_1.buildAddressLlmPredecomposeContractV1)({
sourceMessage: userMessage,
canonicalMessage: userMessage
}),
fallbackRuleHit: null,
sanitizedUserMessage: sanitizeAddressMessageForFallback(userMessage),
toolGateDecision: null,
toolGateReason: null
};
const addressInputMessage = toNonEmptyString(addressPreDecompose?.effectiveMessage) ?? userMessage;
const carryover = resolveAddressFollowupCarryoverContext(userMessage, session.items, addressInputMessage, addressPreDecompose);
const orchestrationDecision = resolveAssistantOrchestrationDecision({
rawUserMessage: userMessage,
effectiveAddressUserMessage: addressInputMessage,
followupContext: carryover?.followupContext ?? null,
llmPreDecomposeMeta: addressPreDecompose,
useMock: Boolean(payload.useMock)
const addressOrchestrationRuntime = await (0, assistantAddressOrchestrationRuntimeAdapter_1.buildAssistantAddressOrchestrationRuntime)({
userMessage,
sessionItems: session.items,
llmProvider: payload?.llmProvider,
useMock: Boolean(payload.useMock),
featureAddressLlmPredecomposeV1: config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_LLM_PREDECOMPOSE_V1,
runAddressLlmPreDecompose: async () => runAddressLlmPreDecompose(this.normalizerService, payload, userMessage),
buildAddressLlmPredecomposeContractV1: predecomposeContract_1.buildAddressLlmPredecomposeContractV1,
sanitizeAddressMessageForFallback,
toNonEmptyString,
resolveAddressFollowupCarryoverContext,
resolveAssistantOrchestrationDecision,
buildAddressDialogContinuationContractV2
});
const dialogContinuationContract = buildAddressDialogContinuationContractV2(userMessage, addressInputMessage, carryover, addressPreDecompose);
const addressRuntimeMeta = {
...addressPreDecompose,
toolGateDecision: orchestrationDecision.toolGateDecision,
toolGateReason: orchestrationDecision.toolGateReason,
dialogContinuationContract,
orchestrationContract: orchestrationDecision.orchestrationContract
};
const addressPreDecompose = addressOrchestrationRuntime.addressPreDecompose;
const addressInputMessage = addressOrchestrationRuntime.addressInputMessage;
const carryover = addressOrchestrationRuntime.carryover;
const orchestrationDecision = addressOrchestrationRuntime.orchestrationDecision;
const addressRuntimeMeta = addressOrchestrationRuntime.addressRuntimeMeta;
addressRuntimeMetaForDeep = addressRuntimeMeta;
const livingModeDecision = {
mode: orchestrationDecision.livingMode,
reason: orchestrationDecision.livingReason
};
const livingModeDecision = addressOrchestrationRuntime.livingModeDecision;
if (!orchestrationDecision.runAddressLane) {
(0, log_1.logJson)({
timestamp: new Date().toISOString(),
@@ -4637,42 +4619,6 @@ class AssistantService {
const analysisDateHint = runtimeAnalysisContext.as_of_date ?? toNonEmptyString(payload?.context?.period_hint);
const canRetryWithRawUserMessage = compactWhitespace(String(addressInputMessage ?? "").toLowerCase()) !==
compactWhitespace(String(userMessage ?? "").toLowerCase());
const retryAudit = {
attempted: false,
reason: null,
initial_limited_category: null,
retry_message: null,
retry_used_followup_context: false,
retry_result_category: null
};
const withRetryMeta = () => ({
...addressRuntimeMeta,
addressRetryAudit: { ...retryAudit }
});
let pendingLimited = null;
const evaluateAddressLane = (addressLane, messageUsed, carryMeta) => {
if (!addressLane?.handled) {
return null;
}
if (!isRetryableAddressLimitedResult(addressLane)) {
return {
action: "return",
addressLane,
messageUsed,
carryMeta
};
}
if (!pendingLimited) {
pendingLimited = {
addressLane,
messageUsed,
carryMeta
};
}
return {
action: "continue"
};
};
const runAddressLaneAttempt = async (messageUsed, carryMeta) => {
const scopedFollowupContext = mergeFollowupContextWithOrganizationScope(carryMeta?.followupContext ?? null, sessionOrganizationScope.activeOrganization);
if (scopedFollowupContext) {
@@ -4685,48 +4631,20 @@ class AssistantService {
analysisDateHint
});
};
if (shouldPreferContextualLane) {
const contextualAddressLane = await runAddressLaneAttempt(addressInputMessage, carryover);
const decision = evaluateAddressLane(contextualAddressLane, addressInputMessage, carryover);
if (decision?.action === "return") {
return finalizeAddressLaneResponse(decision.addressLane, decision.messageUsed, decision.carryMeta, withRetryMeta());
}
}
const primaryAddressLane = await runAddressLaneAttempt(addressInputMessage, null);
const primaryDecision = evaluateAddressLane(primaryAddressLane, addressInputMessage, null);
if (primaryDecision?.action === "return") {
return finalizeAddressLaneResponse(primaryDecision.addressLane, primaryDecision.messageUsed, primaryDecision.carryMeta, withRetryMeta());
}
if (!shouldPreferContextualLane && carryover?.followupContext) {
const contextualAddressLane = await runAddressLaneAttempt(addressInputMessage, carryover);
const contextualDecision = evaluateAddressLane(contextualAddressLane, addressInputMessage, carryover);
if (contextualDecision?.action === "return") {
return finalizeAddressLaneResponse(contextualDecision.addressLane, contextualDecision.messageUsed, contextualDecision.carryMeta, withRetryMeta());
}
}
if (pendingLimited && canRetryWithRawUserMessage) {
retryAudit.attempted = true;
retryAudit.reason = "limited_result_retry_with_raw_message";
retryAudit.initial_limited_category = pendingLimited.addressLane?.debug?.limited_reason_category ?? null;
retryAudit.retry_message = userMessage;
if (carryover?.followupContext) {
retryAudit.retry_used_followup_context = true;
const rawContextualLane = await runAddressLaneAttempt(userMessage, carryover);
const rawContextualDecision = evaluateAddressLane(rawContextualLane, userMessage, carryover);
if (rawContextualDecision?.action === "return") {
retryAudit.retry_result_category = rawContextualDecision.addressLane?.debug?.limited_reason_category ?? null;
return finalizeAddressLaneResponse(rawContextualDecision.addressLane, rawContextualDecision.messageUsed, rawContextualDecision.carryMeta, withRetryMeta());
}
}
const rawPrimaryLane = await runAddressLaneAttempt(userMessage, null);
retryAudit.retry_result_category = rawPrimaryLane?.debug?.limited_reason_category ?? null;
const rawPrimaryDecision = evaluateAddressLane(rawPrimaryLane, userMessage, null);
if (rawPrimaryDecision?.action === "return") {
return finalizeAddressLaneResponse(rawPrimaryDecision.addressLane, rawPrimaryDecision.messageUsed, rawPrimaryDecision.carryMeta, withRetryMeta());
}
}
if (pendingLimited) {
return finalizeAddressLaneResponse(pendingLimited.addressLane, pendingLimited.messageUsed, pendingLimited.carryMeta, withRetryMeta());
const addressLaneRuntime = await (0, assistantAddressLaneRuntimeAdapter_1.runAssistantAddressLaneRuntime)({
userMessage,
addressInputMessage,
carryover,
shouldPreferContextualLane,
canRetryWithRawUserMessage,
runAddressLaneAttempt,
isRetryableAddressLimitedResult
});
if (addressLaneRuntime.handled && addressLaneRuntime.selection) {
return finalizeAddressLaneResponse(addressLaneRuntime.selection.addressLane, addressLaneRuntime.selection.messageUsed, addressLaneRuntime.selection.carryMeta, {
...addressRuntimeMeta,
addressRetryAudit: { ...addressLaneRuntime.retryAudit }
});
}
}
}