ГЛОБАЛЬНЫЙ РЕФАКТОРИНГ АРХИТЕКТУРЫ - Рефакторинг этапов 2.45 - объединены три выделенных слоя (NormalizationAttempt + AnalysisAttempt + ResponseAttempt) в один assistantDeepTurnAttemptRuntimeAdapter, после чего в handleMessage остался один вызов вместо трёх

This commit is contained in:
dctouch 2026-04-10 23:55:11 +03:00
parent fcfcba47b0
commit 5790e25b68
6 changed files with 540 additions and 81 deletions

View File

@ -1405,7 +1405,39 @@ Validation:
- `assistantDeepTurnPackagingRuntimeAdapter.test.ts`
- `assistantWave10SettlementCorrectiveRegression.test.ts`
Status: **In progress (Phase 2.1 + 2.2 + 2.3 + 2.4 + 2.5 + 2.6 + 2.7 + 2.8 + 2.9 + 2.10 + 2.11 + 2.12 + 2.13 + 2.14 + 2.15 + 2.16 + 2.17 + 2.18 + 2.19 + 2.20 + 2.21 + 2.22 + 2.23 + 2.24 + 2.25 + 2.26 + 2.27 + 2.28 + 2.29 + 2.30 + 2.31 + 2.32 + 2.33 + 2.34 + 2.35 + 2.36 + 2.37 + 2.38 + 2.39 + 2.40 + 2.41 + 2.42 + 2.43 + 2.44 completed)**
Implemented in current pass (Phase 2.45):
1. Extracted full deep-turn chain (`normalization -> analysis -> response`) from `assistantService` into dedicated runtime adapter:
- `assistantDeepTurnAttemptRuntimeAdapter.ts`
- introduced:
- `runAssistantDeepTurnAttemptRuntime(...)`
2. Centralized deep-turn orchestration handoff (behavior-preserving):
- unified composition over existing attempt adapters (`Normalization`, `Analysis`, `Response`);
- preserved followup binding, runtime context propagation, response finalization hooks and investigation-state persistence callbacks.
3. Rewired `assistantService` to consume a single deep-turn runtime adapter call.
4. Added focused unit tests:
- `assistantDeepTurnAttemptRuntimeAdapter.test.ts`
Validation:
1. `npm run build` passed.
2. Targeted living/address/deep followup pack passed:
- `assistantDeepTurnAttemptRuntimeAdapter.test.ts`
- `assistantDeepTurnResponseAttemptRuntimeAdapter.test.ts`
- `assistantDeepTurnAnalysisAttemptRuntimeAdapter.test.ts`
- `assistantDeepTurnAnalysisRuntimeAdapter.test.ts`
- `assistantAddressLaneResponseAttemptRuntimeAdapter.test.ts`
- `assistantLivingChatAttemptRuntimeAdapter.test.ts`
- `assistantAddressLaneAttemptRuntimeAdapter.test.ts`
- `assistantUserTurnBootstrapRuntimeAdapter.test.ts`
- `assistantLivingChatLlmRuntimeAdapter.test.ts`
- `assistantLivingChatHandlerRuntimeAdapter.test.ts`
- `assistantLivingChatRuntimeAdapter.test.ts`
- `assistantAddressRuntimeAdapter.test.ts`
- `assistantAddressLaneResponseRuntimeAdapter.test.ts`
- `assistantDeepTurnResponseRuntimeAdapter.test.ts`
- `assistantDeepTurnPackagingRuntimeAdapter.test.ts`
- `assistantWave10SettlementCorrectiveRegression.test.ts`
Status: **In progress (Phase 2.1 + 2.2 + 2.3 + 2.4 + 2.5 + 2.6 + 2.7 + 2.8 + 2.9 + 2.10 + 2.11 + 2.12 + 2.13 + 2.14 + 2.15 + 2.16 + 2.17 + 2.18 + 2.19 + 2.20 + 2.21 + 2.22 + 2.23 + 2.24 + 2.25 + 2.26 + 2.27 + 2.28 + 2.29 + 2.30 + 2.31 + 2.32 + 2.33 + 2.34 + 2.35 + 2.36 + 2.37 + 2.38 + 2.39 + 2.40 + 2.41 + 2.42 + 2.43 + 2.44 + 2.45 completed)**
## Stage 3 (P2): Hybrid Semantic Layer (LLM + Deterministic Guards)

View File

@ -0,0 +1,88 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.runAssistantDeepTurnAttemptRuntime = runAssistantDeepTurnAttemptRuntime;
const assistantDeepTurnNormalizationRuntimeAdapter_1 = require("./assistantDeepTurnNormalizationRuntimeAdapter");
const assistantDeepTurnAnalysisAttemptRuntimeAdapter_1 = require("./assistantDeepTurnAnalysisAttemptRuntimeAdapter");
const assistantDeepTurnResponseAttemptRuntimeAdapter_1 = require("./assistantDeepTurnResponseAttemptRuntimeAdapter");
async function runAssistantDeepTurnAttemptRuntime(input) {
const runDeepTurnNormalizationRuntimeSafe = input.runDeepTurnNormalizationRuntime ?? assistantDeepTurnNormalizationRuntimeAdapter_1.buildAssistantDeepTurnNormalizationRuntime;
const runDeepTurnAnalysisAttemptRuntimeSafe = input.runDeepTurnAnalysisAttemptRuntime ?? assistantDeepTurnAnalysisAttemptRuntimeAdapter_1.runAssistantDeepTurnAnalysisAttemptRuntime;
const runDeepTurnResponseAttemptRuntimeSafe = input.runDeepTurnResponseAttemptRuntime ?? assistantDeepTurnResponseAttemptRuntimeAdapter_1.runAssistantDeepTurnResponseAttemptRuntime;
const normalizationRuntime = await runDeepTurnNormalizationRuntimeSafe({
userMessage: input.userMessage,
payload: input.payload,
featureInvestigationStateV1: input.featureInvestigationStateV1,
featureStateFollowupBindingV1: input.featureStateFollowupBindingV1,
sessionInvestigationState: input.sessionInvestigationState,
buildFollowupStateBinding: input.buildFollowupStateBinding,
normalize: input.normalize
});
const followupBinding = normalizationRuntime.followupBinding;
const normalized = normalizationRuntime.normalized;
const deepTurnAnalysisRuntime = await runDeepTurnAnalysisAttemptRuntimeSafe({
userMessage: input.userMessage,
normalizedPayload: normalized.normalized,
routeSummary: normalized.route_hint_summary,
runtimeAnalysisContext: input.runtimeAnalysisContext,
followupUsage: followupBinding.usage,
investigationState: input.sessionInvestigationState,
featureAnswerPolicyV11: input.featureAnswerPolicyV11,
featureProblemCentricAnswerV1: input.featureProblemCentricAnswerV1,
featureLifecycleAnswerV1: input.featureLifecycleAnswerV1,
resolveBusinessScopeAlignment: input.resolveBusinessScopeAlignment,
inferP0DomainFromMessage: input.inferP0DomainFromMessage,
resolveBusinessScopeFromLiveContext: input.resolveBusinessScopeFromLiveContext,
extractRequirements: input.extractRequirements,
toExecutionPlan: input.toExecutionPlan,
enforceRbpLiveRoutePlan: input.enforceRbpLiveRoutePlan,
enforceFaLiveRoutePlan: input.enforceFaLiveRoutePlan,
executeRouteRuntime: input.executeRouteRuntime,
mapNoRouteReason: input.mapNoRouteReason,
buildSkippedResult: input.buildSkippedResult,
evaluateCoverage: input.evaluateCoverage,
checkGrounding: input.checkGrounding,
collectRbpLiveRouteAudit: input.collectRbpLiveRouteAudit,
collectFaLiveRouteAudit: input.collectFaLiveRouteAudit,
hasExplicitPeriodAnchor: input.hasExplicitPeriodAnchor
});
const deepTurnResponseRuntime = runDeepTurnResponseAttemptRuntimeSafe({
featureInvestigationStateV1: input.featureInvestigationStateV1,
featureContractsV11: input.featureContractsV11,
featureAnswerPolicyV11: input.featureAnswerPolicyV11,
sessionId: input.sessionId,
questionId: input.questionId,
userMessage: input.userMessage,
normalized: {
trace_id: normalized.trace_id,
prompt_version: normalized.prompt_version,
schema_version: normalized.schema_version,
normalized: normalized.normalized
},
normalizedQuestion: followupBinding.normalizedQuestion,
deepTurnAnalysisRuntime,
runtimeAnalysisContext: input.runtimeAnalysisContext,
followupStateUsage: followupBinding.usage,
followupApplied: Boolean(followupBinding.usage?.applied),
previousInvestigationState: input.sessionInvestigationState,
addressRuntimeMetaForDeep: input.addressRuntimeMetaForDeep,
extractDroppedIntentSegments: input.extractDroppedIntentSegments,
buildDebugRoutes: input.buildDebugRoutes,
extractExecutionState: input.extractExecutionState,
sanitizeReply: input.sanitizeReply,
persistInvestigationState: input.persistInvestigationState,
messageIdFactory: input.messageIdFactory,
appendItem: input.appendItem,
getSession: input.getSession,
persistSession: input.persistSession,
cloneConversation: input.cloneConversation,
logEvent: input.logEvent,
runPackagingRuntime: input.runPackagingRuntime,
runFinalizeDeepTurn: input.runFinalizeDeepTurn
});
return {
response: deepTurnResponseRuntime.response,
debug: deepTurnResponseRuntime.debug,
normalizationRuntime,
deepTurnAnalysisRuntime
};
}

View File

@ -64,9 +64,7 @@ const capabilitiesRegistry_1 = __importStar(require("./capabilitiesRegistry"));
const assistantCanon_1 = __importStar(require("./assistantCanon"));
const assistantAddressLaneResponseAttemptRuntimeAdapter_1 = __importStar(require("./assistantAddressLaneResponseAttemptRuntimeAdapter"));
const assistantCoverageGrounding_1 = __importStar(require("./assistantCoverageGrounding"));
const assistantDeepTurnAnalysisAttemptRuntimeAdapter_1 = __importStar(require("./assistantDeepTurnAnalysisAttemptRuntimeAdapter"));
const assistantDeepTurnNormalizationRuntimeAdapter_1 = __importStar(require("./assistantDeepTurnNormalizationRuntimeAdapter"));
const assistantDeepTurnResponseAttemptRuntimeAdapter_1 = __importStar(require("./assistantDeepTurnResponseAttemptRuntimeAdapter"));
const assistantDeepTurnAttemptRuntimeAdapter_1 = __importStar(require("./assistantDeepTurnAttemptRuntimeAdapter"));
const assistantAddressRuntimeAdapter_1 = __importStar(require("./assistantAddressRuntimeAdapter"));
const assistantAddressLaneAttemptRuntimeAdapter_1 = __importStar(require("./assistantAddressLaneAttemptRuntimeAdapter"));
const assistantLivingChatAttemptRuntimeAdapter_1 = __importStar(require("./assistantLivingChatAttemptRuntimeAdapter"));
@ -4493,27 +4491,22 @@ class AssistantService {
if (addressRuntime.handled && addressRuntime.response) {
return addressRuntime.response;
}
const normalizationRuntime = await (0, assistantDeepTurnNormalizationRuntimeAdapter_1.buildAssistantDeepTurnNormalizationRuntime)({
const deepTurnRuntime = await (0, assistantDeepTurnAttemptRuntimeAdapter_1.runAssistantDeepTurnAttemptRuntime)({
sessionId,
questionId: userItem.message_id,
userMessage,
payload,
runtimeAnalysisContext,
sessionInvestigationState: session.investigation_state,
addressRuntimeMetaForDeep,
featureInvestigationStateV1: config_1.FEATURE_ASSISTANT_INVESTIGATION_STATE_V1,
featureStateFollowupBindingV1: config_1.FEATURE_ASSISTANT_STATE_FOLLOWUP_BINDING_V1,
sessionInvestigationState: session.investigation_state,
buildFollowupStateBinding,
normalize: (normalizePayload) => this.normalizerService.normalize(normalizePayload)
});
const followupBinding = normalizationRuntime.followupBinding;
const normalized = normalizationRuntime.normalized;
const deepTurnAnalysisRuntime = await (0, assistantDeepTurnAnalysisAttemptRuntimeAdapter_1.runAssistantDeepTurnAnalysisAttemptRuntime)({
userMessage,
normalizedPayload: normalized.normalized,
routeSummary: normalized.route_hint_summary,
runtimeAnalysisContext,
followupUsage: followupBinding.usage,
investigationState: session.investigation_state,
featureContractsV11: config_1.FEATURE_ASSISTANT_CONTRACTS_V11,
featureAnswerPolicyV11: config_1.FEATURE_ASSISTANT_ANSWER_POLICY_V11,
featureProblemCentricAnswerV1: config_1.FEATURE_ASSISTANT_PROBLEM_CENTRIC_ANSWER_V1,
featureLifecycleAnswerV1: config_1.FEATURE_ASSISTANT_LIFECYCLE_ANSWER_V1,
buildFollowupStateBinding,
normalize: (normalizePayload) => this.normalizerService.normalize(normalizePayload),
resolveBusinessScopeAlignment,
inferP0DomainFromMessage,
resolveBusinessScopeFromLiveContext,
@ -4528,28 +4521,7 @@ class AssistantService {
checkGrounding,
collectRbpLiveRouteAudit,
collectFaLiveRouteAudit,
hasExplicitPeriodAnchor: (normalizedPayload) => hasExplicitPeriodAnchorFromNormalized(normalizedPayload)
});
const deepTurnResponseRuntime = (0, assistantDeepTurnResponseAttemptRuntimeAdapter_1.runAssistantDeepTurnResponseAttemptRuntime)({
featureInvestigationStateV1: config_1.FEATURE_ASSISTANT_INVESTIGATION_STATE_V1,
featureContractsV11: config_1.FEATURE_ASSISTANT_CONTRACTS_V11,
featureAnswerPolicyV11: config_1.FEATURE_ASSISTANT_ANSWER_POLICY_V11,
sessionId,
questionId: userItem.message_id,
userMessage,
normalized: {
trace_id: normalized.trace_id,
prompt_version: normalized.prompt_version,
schema_version: normalized.schema_version,
normalized: normalized.normalized
},
normalizedQuestion: followupBinding.normalizedQuestion,
deepTurnAnalysisRuntime,
runtimeAnalysisContext,
followupStateUsage: followupBinding.usage,
followupApplied: Boolean(followupBinding.usage?.applied),
previousInvestigationState: session.investigation_state,
addressRuntimeMetaForDeep,
hasExplicitPeriodAnchor: (normalizedPayload) => hasExplicitPeriodAnchorFromNormalized(normalizedPayload),
extractDroppedIntentSegments: (normalizedPayload) => extractDiscardedIntentSegments(normalizedPayload),
buildDebugRoutes: (routeSummary) => toDebugRoutes(routeSummary),
extractExecutionState: (normalizedPayload) => extractExecutionState(normalizedPayload),
@ -4562,7 +4534,7 @@ class AssistantService {
cloneConversation: (items) => cloneItems(items),
logEvent: (payload) => (0, log_1.logJson)(payload)
});
return deepTurnResponseRuntime.response;
return deepTurnRuntime.response;
}
}
exports.AssistantService = AssistantService;

View File

@ -0,0 +1,174 @@
import type { AssistantMessageResponsePayload } from "../types/assistant";
import type { InvestigationStateWithProblemUnits } from "../types/stage2ProblemUnits";
import {
buildAssistantDeepTurnNormalizationRuntime,
type BuildAssistantDeepTurnNormalizationRuntimeInput,
type BuildAssistantDeepTurnNormalizationRuntimeOutput
} from "./assistantDeepTurnNormalizationRuntimeAdapter";
import {
runAssistantDeepTurnAnalysisAttemptRuntime,
type RunAssistantDeepTurnAnalysisAttemptRuntimeInput
} from "./assistantDeepTurnAnalysisAttemptRuntimeAdapter";
import {
runAssistantDeepTurnResponseAttemptRuntime,
type RunAssistantDeepTurnResponseAttemptRuntimeInput
} from "./assistantDeepTurnResponseAttemptRuntimeAdapter";
import type { RunAssistantDeepTurnAnalysisRuntimeOutput } from "./assistantDeepTurnAnalysisRuntimeAdapter";
export interface RunAssistantDeepTurnAttemptRuntimeInput<ResponseType = AssistantMessageResponsePayload> {
sessionId: string;
questionId: string;
userMessage: string;
payload: BuildAssistantDeepTurnNormalizationRuntimeInput["payload"];
runtimeAnalysisContext: RunAssistantDeepTurnAnalysisAttemptRuntimeInput["runtimeAnalysisContext"];
sessionInvestigationState: InvestigationStateWithProblemUnits | null | undefined;
addressRuntimeMetaForDeep: unknown;
featureInvestigationStateV1: boolean;
featureStateFollowupBindingV1: boolean;
featureContractsV11: boolean;
featureAnswerPolicyV11: boolean;
featureProblemCentricAnswerV1: boolean;
featureLifecycleAnswerV1: boolean;
buildFollowupStateBinding: BuildAssistantDeepTurnNormalizationRuntimeInput["buildFollowupStateBinding"];
normalize: BuildAssistantDeepTurnNormalizationRuntimeInput["normalize"];
resolveBusinessScopeAlignment: RunAssistantDeepTurnAnalysisAttemptRuntimeInput["resolveBusinessScopeAlignment"];
inferP0DomainFromMessage: RunAssistantDeepTurnAnalysisAttemptRuntimeInput["inferP0DomainFromMessage"];
resolveBusinessScopeFromLiveContext: RunAssistantDeepTurnAnalysisAttemptRuntimeInput["resolveBusinessScopeFromLiveContext"];
extractRequirements: RunAssistantDeepTurnAnalysisAttemptRuntimeInput["extractRequirements"];
toExecutionPlan: RunAssistantDeepTurnAnalysisAttemptRuntimeInput["toExecutionPlan"];
enforceRbpLiveRoutePlan: RunAssistantDeepTurnAnalysisAttemptRuntimeInput["enforceRbpLiveRoutePlan"];
enforceFaLiveRoutePlan: RunAssistantDeepTurnAnalysisAttemptRuntimeInput["enforceFaLiveRoutePlan"];
executeRouteRuntime: RunAssistantDeepTurnAnalysisAttemptRuntimeInput["executeRouteRuntime"];
mapNoRouteReason: RunAssistantDeepTurnAnalysisAttemptRuntimeInput["mapNoRouteReason"];
buildSkippedResult: RunAssistantDeepTurnAnalysisAttemptRuntimeInput["buildSkippedResult"];
evaluateCoverage: RunAssistantDeepTurnAnalysisAttemptRuntimeInput["evaluateCoverage"];
checkGrounding: RunAssistantDeepTurnAnalysisAttemptRuntimeInput["checkGrounding"];
collectRbpLiveRouteAudit: RunAssistantDeepTurnAnalysisAttemptRuntimeInput["collectRbpLiveRouteAudit"];
collectFaLiveRouteAudit: RunAssistantDeepTurnAnalysisAttemptRuntimeInput["collectFaLiveRouteAudit"];
hasExplicitPeriodAnchor: RunAssistantDeepTurnAnalysisAttemptRuntimeInput["hasExplicitPeriodAnchor"];
extractDroppedIntentSegments: RunAssistantDeepTurnResponseAttemptRuntimeInput<ResponseType>["extractDroppedIntentSegments"];
buildDebugRoutes: RunAssistantDeepTurnResponseAttemptRuntimeInput<ResponseType>["buildDebugRoutes"];
extractExecutionState: RunAssistantDeepTurnResponseAttemptRuntimeInput<ResponseType>["extractExecutionState"];
sanitizeReply: RunAssistantDeepTurnResponseAttemptRuntimeInput<ResponseType>["sanitizeReply"];
persistInvestigationState: RunAssistantDeepTurnResponseAttemptRuntimeInput<ResponseType>["persistInvestigationState"];
messageIdFactory: RunAssistantDeepTurnResponseAttemptRuntimeInput<ResponseType>["messageIdFactory"];
appendItem: RunAssistantDeepTurnResponseAttemptRuntimeInput<ResponseType>["appendItem"];
getSession: RunAssistantDeepTurnResponseAttemptRuntimeInput<ResponseType>["getSession"];
persistSession: RunAssistantDeepTurnResponseAttemptRuntimeInput<ResponseType>["persistSession"];
cloneConversation: RunAssistantDeepTurnResponseAttemptRuntimeInput<ResponseType>["cloneConversation"];
logEvent: RunAssistantDeepTurnResponseAttemptRuntimeInput<ResponseType>["logEvent"];
runPackagingRuntime?: RunAssistantDeepTurnResponseAttemptRuntimeInput<ResponseType>["runPackagingRuntime"];
runFinalizeDeepTurn?: RunAssistantDeepTurnResponseAttemptRuntimeInput<ResponseType>["runFinalizeDeepTurn"];
runDeepTurnNormalizationRuntime?: (
input: BuildAssistantDeepTurnNormalizationRuntimeInput
) => Promise<BuildAssistantDeepTurnNormalizationRuntimeOutput>;
runDeepTurnAnalysisAttemptRuntime?: (
input: RunAssistantDeepTurnAnalysisAttemptRuntimeInput
) => Promise<RunAssistantDeepTurnAnalysisRuntimeOutput>;
runDeepTurnResponseAttemptRuntime?: (
input: RunAssistantDeepTurnResponseAttemptRuntimeInput<ResponseType>
) => {
response: ResponseType;
debug: Record<string, unknown>;
};
}
export interface RunAssistantDeepTurnAttemptRuntimeOutput<ResponseType = AssistantMessageResponsePayload> {
response: ResponseType;
debug: Record<string, unknown>;
normalizationRuntime: BuildAssistantDeepTurnNormalizationRuntimeOutput;
deepTurnAnalysisRuntime: RunAssistantDeepTurnAnalysisRuntimeOutput;
}
export async function runAssistantDeepTurnAttemptRuntime<ResponseType = AssistantMessageResponsePayload>(
input: RunAssistantDeepTurnAttemptRuntimeInput<ResponseType>
): Promise<RunAssistantDeepTurnAttemptRuntimeOutput<ResponseType>> {
const runDeepTurnNormalizationRuntimeSafe =
input.runDeepTurnNormalizationRuntime ?? buildAssistantDeepTurnNormalizationRuntime;
const runDeepTurnAnalysisAttemptRuntimeSafe =
input.runDeepTurnAnalysisAttemptRuntime ?? runAssistantDeepTurnAnalysisAttemptRuntime;
const runDeepTurnResponseAttemptRuntimeSafe =
input.runDeepTurnResponseAttemptRuntime ?? runAssistantDeepTurnResponseAttemptRuntime;
const normalizationRuntime = await runDeepTurnNormalizationRuntimeSafe({
userMessage: input.userMessage,
payload: input.payload,
featureInvestigationStateV1: input.featureInvestigationStateV1,
featureStateFollowupBindingV1: input.featureStateFollowupBindingV1,
sessionInvestigationState: input.sessionInvestigationState,
buildFollowupStateBinding: input.buildFollowupStateBinding,
normalize: input.normalize
});
const followupBinding = normalizationRuntime.followupBinding;
const normalized = normalizationRuntime.normalized;
const deepTurnAnalysisRuntime = await runDeepTurnAnalysisAttemptRuntimeSafe({
userMessage: input.userMessage,
normalizedPayload: normalized.normalized,
routeSummary: normalized.route_hint_summary,
runtimeAnalysisContext: input.runtimeAnalysisContext,
followupUsage: followupBinding.usage,
investigationState: input.sessionInvestigationState,
featureAnswerPolicyV11: input.featureAnswerPolicyV11,
featureProblemCentricAnswerV1: input.featureProblemCentricAnswerV1,
featureLifecycleAnswerV1: input.featureLifecycleAnswerV1,
resolveBusinessScopeAlignment: input.resolveBusinessScopeAlignment,
inferP0DomainFromMessage: input.inferP0DomainFromMessage,
resolveBusinessScopeFromLiveContext: input.resolveBusinessScopeFromLiveContext,
extractRequirements: input.extractRequirements,
toExecutionPlan: input.toExecutionPlan,
enforceRbpLiveRoutePlan: input.enforceRbpLiveRoutePlan,
enforceFaLiveRoutePlan: input.enforceFaLiveRoutePlan,
executeRouteRuntime: input.executeRouteRuntime,
mapNoRouteReason: input.mapNoRouteReason,
buildSkippedResult: input.buildSkippedResult,
evaluateCoverage: input.evaluateCoverage,
checkGrounding: input.checkGrounding,
collectRbpLiveRouteAudit: input.collectRbpLiveRouteAudit,
collectFaLiveRouteAudit: input.collectFaLiveRouteAudit,
hasExplicitPeriodAnchor: input.hasExplicitPeriodAnchor
});
const deepTurnResponseRuntime = runDeepTurnResponseAttemptRuntimeSafe({
featureInvestigationStateV1: input.featureInvestigationStateV1,
featureContractsV11: input.featureContractsV11,
featureAnswerPolicyV11: input.featureAnswerPolicyV11,
sessionId: input.sessionId,
questionId: input.questionId,
userMessage: input.userMessage,
normalized: {
trace_id: normalized.trace_id,
prompt_version: normalized.prompt_version,
schema_version: normalized.schema_version,
normalized: normalized.normalized
},
normalizedQuestion: followupBinding.normalizedQuestion,
deepTurnAnalysisRuntime,
runtimeAnalysisContext: input.runtimeAnalysisContext,
followupStateUsage: followupBinding.usage,
followupApplied: Boolean((followupBinding.usage as { applied?: unknown } | null)?.applied),
previousInvestigationState: input.sessionInvestigationState,
addressRuntimeMetaForDeep: input.addressRuntimeMetaForDeep,
extractDroppedIntentSegments: input.extractDroppedIntentSegments,
buildDebugRoutes: input.buildDebugRoutes,
extractExecutionState: input.extractExecutionState,
sanitizeReply: input.sanitizeReply,
persistInvestigationState: input.persistInvestigationState,
messageIdFactory: input.messageIdFactory,
appendItem: input.appendItem,
getSession: input.getSession,
persistSession: input.persistSession,
cloneConversation: input.cloneConversation,
logEvent: input.logEvent,
runPackagingRuntime: input.runPackagingRuntime,
runFinalizeDeepTurn: input.runFinalizeDeepTurn
});
return {
response: deepTurnResponseRuntime.response,
debug: deepTurnResponseRuntime.debug,
normalizationRuntime,
deepTurnAnalysisRuntime
};
}

View File

@ -18,9 +18,7 @@ import * as capabilitiesRegistry_1 from "./capabilitiesRegistry";
import * as assistantCanon_1 from "./assistantCanon";
import * as assistantAddressLaneResponseAttemptRuntimeAdapter_1 from "./assistantAddressLaneResponseAttemptRuntimeAdapter";
import * as assistantCoverageGrounding_1 from "./assistantCoverageGrounding";
import * as assistantDeepTurnAnalysisAttemptRuntimeAdapter_1 from "./assistantDeepTurnAnalysisAttemptRuntimeAdapter";
import * as assistantDeepTurnNormalizationRuntimeAdapter_1 from "./assistantDeepTurnNormalizationRuntimeAdapter";
import * as assistantDeepTurnResponseAttemptRuntimeAdapter_1 from "./assistantDeepTurnResponseAttemptRuntimeAdapter";
import * as assistantDeepTurnAttemptRuntimeAdapter_1 from "./assistantDeepTurnAttemptRuntimeAdapter";
import * as assistantAddressRuntimeAdapter_1 from "./assistantAddressRuntimeAdapter";
import * as assistantAddressLaneAttemptRuntimeAdapter_1 from "./assistantAddressLaneAttemptRuntimeAdapter";
import * as assistantLivingChatAttemptRuntimeAdapter_1 from "./assistantLivingChatAttemptRuntimeAdapter";
@ -4448,27 +4446,22 @@ export class AssistantService {
if (addressRuntime.handled && addressRuntime.response) {
return addressRuntime.response;
}
const normalizationRuntime = await (0, assistantDeepTurnNormalizationRuntimeAdapter_1.buildAssistantDeepTurnNormalizationRuntime)({
const deepTurnRuntime = await (0, assistantDeepTurnAttemptRuntimeAdapter_1.runAssistantDeepTurnAttemptRuntime)({
sessionId,
questionId: userItem.message_id,
userMessage,
payload,
runtimeAnalysisContext,
sessionInvestigationState: session.investigation_state,
addressRuntimeMetaForDeep,
featureInvestigationStateV1: config_1.FEATURE_ASSISTANT_INVESTIGATION_STATE_V1,
featureStateFollowupBindingV1: config_1.FEATURE_ASSISTANT_STATE_FOLLOWUP_BINDING_V1,
sessionInvestigationState: session.investigation_state,
buildFollowupStateBinding,
normalize: (normalizePayload) => this.normalizerService.normalize(normalizePayload)
});
const followupBinding = normalizationRuntime.followupBinding;
const normalized = normalizationRuntime.normalized;
const deepTurnAnalysisRuntime = await (0, assistantDeepTurnAnalysisAttemptRuntimeAdapter_1.runAssistantDeepTurnAnalysisAttemptRuntime)({
userMessage,
normalizedPayload: normalized.normalized,
routeSummary: normalized.route_hint_summary,
runtimeAnalysisContext,
followupUsage: followupBinding.usage,
investigationState: session.investigation_state,
featureContractsV11: config_1.FEATURE_ASSISTANT_CONTRACTS_V11,
featureAnswerPolicyV11: config_1.FEATURE_ASSISTANT_ANSWER_POLICY_V11,
featureProblemCentricAnswerV1: config_1.FEATURE_ASSISTANT_PROBLEM_CENTRIC_ANSWER_V1,
featureLifecycleAnswerV1: config_1.FEATURE_ASSISTANT_LIFECYCLE_ANSWER_V1,
buildFollowupStateBinding,
normalize: (normalizePayload) => this.normalizerService.normalize(normalizePayload),
resolveBusinessScopeAlignment,
inferP0DomainFromMessage,
resolveBusinessScopeFromLiveContext,
@ -4483,28 +4476,7 @@ export class AssistantService {
checkGrounding,
collectRbpLiveRouteAudit,
collectFaLiveRouteAudit,
hasExplicitPeriodAnchor: (normalizedPayload) => hasExplicitPeriodAnchorFromNormalized(normalizedPayload)
});
const deepTurnResponseRuntime = (0, assistantDeepTurnResponseAttemptRuntimeAdapter_1.runAssistantDeepTurnResponseAttemptRuntime)({
featureInvestigationStateV1: config_1.FEATURE_ASSISTANT_INVESTIGATION_STATE_V1,
featureContractsV11: config_1.FEATURE_ASSISTANT_CONTRACTS_V11,
featureAnswerPolicyV11: config_1.FEATURE_ASSISTANT_ANSWER_POLICY_V11,
sessionId,
questionId: userItem.message_id,
userMessage,
normalized: {
trace_id: normalized.trace_id,
prompt_version: normalized.prompt_version,
schema_version: normalized.schema_version,
normalized: normalized.normalized
},
normalizedQuestion: followupBinding.normalizedQuestion,
deepTurnAnalysisRuntime,
runtimeAnalysisContext,
followupStateUsage: followupBinding.usage,
followupApplied: Boolean(followupBinding.usage?.applied),
previousInvestigationState: session.investigation_state,
addressRuntimeMetaForDeep,
hasExplicitPeriodAnchor: (normalizedPayload) => hasExplicitPeriodAnchorFromNormalized(normalizedPayload),
extractDroppedIntentSegments: (normalizedPayload) => extractDiscardedIntentSegments(normalizedPayload),
buildDebugRoutes: (routeSummary) => toDebugRoutes(routeSummary),
extractExecutionState: (normalizedPayload) => extractExecutionState(normalizedPayload),
@ -4517,6 +4489,6 @@ export class AssistantService {
cloneConversation: (items) => cloneItems(items),
logEvent: (payload) => (0, log_1.logJson)(payload)
});
return deepTurnResponseRuntime.response;
return deepTurnRuntime.response;
}
}

View File

@ -0,0 +1,221 @@
import { describe, expect, it, vi } from "vitest";
import { runAssistantDeepTurnAttemptRuntime } from "../src/services/assistantDeepTurnAttemptRuntimeAdapter";
function buildInput(overrides: Record<string, unknown> = {}) {
return {
sessionId: "asst-1",
questionId: "msg-q1",
userMessage: "почему не закрыт долг",
payload: {
llmProvider: "openai",
apiKey: "key",
model: "gpt-5",
baseUrl: "http://localhost",
temperature: 0.2,
maxOutputTokens: 400,
context: {}
},
runtimeAnalysisContext: {
active: true,
as_of_date: "2020-07-31",
period_from: null,
period_to: null,
source: "analysis_context"
},
sessionInvestigationState: null,
addressRuntimeMetaForDeep: null,
featureInvestigationStateV1: true,
featureStateFollowupBindingV1: true,
featureContractsV11: true,
featureAnswerPolicyV11: true,
featureProblemCentricAnswerV1: true,
featureLifecycleAnswerV1: true,
buildFollowupStateBinding: () => ({
normalizedQuestion: "normalized-question",
mergedContext: {},
usage: null
}),
normalize: async () =>
({
trace_id: "trace-1",
prompt_version: "normalizer_v2_0_2",
schema_version: "normalized_query_v2_0_2",
normalized: { fragments: [] },
route_hint_summary: { mode: "deterministic_v2", decisions: [] }
}) as any,
resolveBusinessScopeAlignment: ({ routeSummary }) => ({
route_summary_resolved: routeSummary
}),
inferP0DomainFromMessage: () => null,
resolveBusinessScopeFromLiveContext: ({ current }) => current,
extractRequirements: () => ({ requirements: [], byFragment: new Map() }),
toExecutionPlan: () => [],
enforceRbpLiveRoutePlan: ({ executionPlan }) => ({ executionPlan, audit: {} }),
enforceFaLiveRoutePlan: ({ executionPlan }) => ({ executionPlan, audit: {} }),
executeRouteRuntime: async () => ({
status: "ok",
result_type: "summary",
items: [],
summary: {},
evidence: [],
limitations: []
}),
mapNoRouteReason: () => "no_route",
buildSkippedResult: () => ({}) as any,
evaluateCoverage: () => ({ requirements: [], coverage: {} }),
checkGrounding: () => ({ status: "no_grounded_answer", reasons: [] }),
collectRbpLiveRouteAudit: () => ({}),
collectFaLiveRouteAudit: () => ({}),
hasExplicitPeriodAnchor: () => false,
extractDroppedIntentSegments: () => [],
buildDebugRoutes: () => [],
extractExecutionState: () => [],
sanitizeReply: (value: string) => value,
persistInvestigationState: () => {},
messageIdFactory: () => "msg-a1",
appendItem: () => {},
getSession: () => ({ session_id: "asst-1", items: [] }),
persistSession: () => {},
cloneConversation: () => [],
logEvent: () => {},
...overrides
} as any;
}
describe("assistant deep turn attempt runtime adapter", () => {
it("orchestrates normalization, analysis and response attempts in order", async () => {
const callOrder: string[] = [];
const normalizationRuntime = {
followupBinding: {
normalizedQuestion: "NQ",
mergedContext: {},
usage: { applied: true }
},
normalizePayload: { userQuestion: "NQ" },
normalized: {
trace_id: "trace-1",
prompt_version: "normalizer_v2_0_2",
schema_version: "normalized_query_v2_0_2",
normalized: { fragments: [] },
route_hint_summary: { mode: "deterministic_v2", decisions: [] }
}
} as any;
const analysisRuntime = {
resolvedRouteSummary: { mode: "deterministic_v2", decisions: [] },
requirementExtraction: { requirements: [], byFragment: new Map() },
coverageEvaluation: { requirements: [], coverage: {} },
groundingCheck: { status: "no_grounded_answer", reasons: [] },
executionPlan: [],
retrievalCalls: [],
retrievalResultsRaw: [],
retrievalResults: [],
questionTypeClass: "single_fact_lookup",
companyAnchors: {},
businessScopeResolution: {},
temporalGuard: {},
polarityGuardResult: { audit: {} },
claimAnchorAudit: { claim_type: "unknown" },
targetedEvidenceResult: { audit: {} },
evidenceGateResult: { audit: {} },
rbpLiveRouteAudit: {},
faLiveRouteAudit: {},
groundedAnswerEligibilityGuard: {},
composition: { reply_type: "partial_coverage" }
} as any;
const runDeepTurnNormalizationRuntime = vi.fn(async () => {
callOrder.push("normalization");
return normalizationRuntime;
});
const runDeepTurnAnalysisAttemptRuntime = vi.fn(async (input) => {
callOrder.push("analysis");
expect(input.normalizedPayload).toEqual(normalizationRuntime.normalized.normalized);
expect(input.routeSummary).toEqual(normalizationRuntime.normalized.route_hint_summary);
expect(input.followupUsage).toEqual({ applied: true });
return analysisRuntime;
});
const runDeepTurnResponseAttemptRuntime = vi.fn((input) => {
callOrder.push("response");
expect(input.normalizedQuestion).toBe("NQ");
expect(input.deepTurnAnalysisRuntime).toBe(analysisRuntime);
expect(input.followupApplied).toBe(true);
return {
response: { ok: true },
debug: { trace_id: "trace-1" }
};
});
const runtime = await runAssistantDeepTurnAttemptRuntime(
buildInput({
runDeepTurnNormalizationRuntime,
runDeepTurnAnalysisAttemptRuntime,
runDeepTurnResponseAttemptRuntime
})
);
expect(callOrder).toEqual(["normalization", "analysis", "response"]);
expect(runtime.response).toEqual({ ok: true });
expect(runtime.debug).toEqual({ trace_id: "trace-1" });
});
it("computes followupApplied=false when followup usage is absent", async () => {
const runDeepTurnNormalizationRuntime = vi.fn(async () => ({
followupBinding: {
normalizedQuestion: "NQ",
mergedContext: {},
usage: null
},
normalizePayload: {},
normalized: {
trace_id: "trace-1",
prompt_version: "normalizer_v2_0_2",
schema_version: "normalized_query_v2_0_2",
normalized: { fragments: [] },
route_hint_summary: null
}
}));
const runDeepTurnResponseAttemptRuntime = vi.fn(() => ({
response: { ok: true },
debug: {}
}));
const investigationState = { session_id: "asst-1" } as any;
await runAssistantDeepTurnAttemptRuntime(
buildInput({
sessionInvestigationState: investigationState,
runDeepTurnNormalizationRuntime,
runDeepTurnAnalysisAttemptRuntime: async () =>
({
resolvedRouteSummary: null,
requirementExtraction: { requirements: [], byFragment: new Map() },
coverageEvaluation: { requirements: [], coverage: {} },
groundingCheck: { status: "no_grounded_answer", reasons: [] },
executionPlan: [],
retrievalCalls: [],
retrievalResultsRaw: [],
retrievalResults: [],
questionTypeClass: "single_fact_lookup",
companyAnchors: {},
businessScopeResolution: {},
temporalGuard: {},
polarityGuardResult: { audit: {} },
claimAnchorAudit: { claim_type: "unknown" },
targetedEvidenceResult: { audit: {} },
evidenceGateResult: { audit: {} },
rbpLiveRouteAudit: {},
faLiveRouteAudit: {},
groundedAnswerEligibilityGuard: {},
composition: { reply_type: "partial_coverage" }
}) as any,
runDeepTurnResponseAttemptRuntime
})
);
expect(runDeepTurnResponseAttemptRuntime).toHaveBeenCalledWith(
expect.objectContaining({
followupApplied: false,
previousInvestigationState: investigationState
})
);
});
});