ГЛОБАЛЬНЫЙ РЕФАКТОРИНГ АРХИТЕКТУРЫ - Рефакторинг этапов 2.49: вынос turnRuntimeDeps (фабрику зависимостей) из assistantService в отдельный deps-adapter, чтобы handleMessage стал совсем тонким.
This commit is contained in:
parent
f1e621fccc
commit
ca467cdecc
|
|
@ -1537,7 +1537,42 @@ 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 + 2.45 + 2.46 + 2.47 + 2.48 completed)**
|
||||
Implemented in current pass (Phase 2.49):
|
||||
1. Extracted turn runtime dependency factory from `assistantService` into dedicated adapter:
|
||||
- `assistantTurnRuntimeDepsAdapter.ts`
|
||||
- introduced:
|
||||
- `buildAssistantTurnRuntimeDeps(...)`
|
||||
2. Rewired `assistantService.handleMessage` to construct runtime deps via adapter (behavior-preserving):
|
||||
- service-level wrappers for `sessions`, `sessionLogger`, `normalizerService`, `dataLayer`, `addressQueryService` moved under deps-adapter boundary;
|
||||
- flags/defaults/helpers remain unchanged semantically and are passed as structured groups (`flags`, `defaults`, `helpers`).
|
||||
3. Added focused unit tests:
|
||||
- `assistantTurnRuntimeDepsAdapter.test.ts`
|
||||
|
||||
Validation:
|
||||
1. `npm run build` passed.
|
||||
2. Targeted living/address/deep followup pack passed:
|
||||
- `assistantTurnRuntimeDepsAdapter.test.ts`
|
||||
- `assistantTurnRuntimeInputBuilder.test.ts`
|
||||
- `assistantTurnAttemptRuntimeAdapter.test.ts`
|
||||
- `assistantAddressAttemptRuntimeAdapter.test.ts`
|
||||
- `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 + 2.46 + 2.47 + 2.48 + 2.49 completed)**
|
||||
|
||||
## Stage 3 (P2): Hybrid Semantic Layer (LLM + Deterministic Guards)
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ const assistantAddressAttemptRuntimeAdapter_1 = __importStar(require("./assistan
|
|||
const assistantCoverageGrounding_1 = __importStar(require("./assistantCoverageGrounding"));
|
||||
const assistantDeepTurnAttemptRuntimeAdapter_1 = __importStar(require("./assistantDeepTurnAttemptRuntimeAdapter"));
|
||||
const assistantTurnAttemptRuntimeAdapter_1 = __importStar(require("./assistantTurnAttemptRuntimeAdapter"));
|
||||
const assistantTurnRuntimeDepsAdapter_1 = __importStar(require("./assistantTurnRuntimeDepsAdapter"));
|
||||
const assistantTurnRuntimeInputBuilder_1 = __importStar(require("./assistantTurnRuntimeInputBuilder"));
|
||||
const assistantUserTurnBootstrapRuntimeAdapter_1 = __importStar(require("./assistantUserTurnBootstrapRuntimeAdapter"));
|
||||
const assistantQueryPlanning_1 = __importStar(require("./assistantQueryPlanning"));
|
||||
|
|
@ -4371,84 +4372,87 @@ class AssistantService {
|
|||
return this.sessions.getSession(sessionId);
|
||||
}
|
||||
async handleMessage(payload) {
|
||||
const turnRuntimeDeps = {
|
||||
ensureSession: (targetSessionId) => this.sessions.ensureSession(targetSessionId),
|
||||
appendItem: (targetSessionId, item) => this.sessions.appendItem(targetSessionId, item),
|
||||
getSession: (targetSessionId) => this.sessions.getSession(targetSessionId),
|
||||
persistSession: (sessionState) => this.sessionLogger.persistSession(sessionState),
|
||||
setInvestigationState: (targetSessionId, snapshot) => this.sessions.setInvestigationState(targetSessionId, snapshot),
|
||||
normalize: (normalizePayload) => this.normalizerService.normalize(normalizePayload),
|
||||
executeRouteRuntime: (route, fragmentText, options) => this.dataLayer.executeRouteRuntime(route, fragmentText, options),
|
||||
tryAddressQueryHandle: (laneMessageUsed, options) => this.addressQueryService.tryHandle(laneMessageUsed, options),
|
||||
const turnRuntimeDeps = (0, assistantTurnRuntimeDepsAdapter_1.buildAssistantTurnRuntimeDeps)({
|
||||
sessions: this.sessions,
|
||||
sessionLogger: this.sessionLogger,
|
||||
normalizerService: this.normalizerService,
|
||||
dataLayer: this.dataLayer,
|
||||
addressQueryService: this.addressQueryService,
|
||||
chatClient: this.chatClient,
|
||||
messageIdFactory: () => `msg-${(0, nanoid_1.nanoid)(10)}`,
|
||||
nowIso: () => new Date().toISOString(),
|
||||
defaultApiKey: process.env.OPENAI_API_KEY ?? "",
|
||||
logEvent: (runtimePayload) => (0, log_1.logJson)(runtimePayload),
|
||||
featureAssistantAddressQueryV1: config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_V1,
|
||||
featureAddressLlmPredecomposeV1: config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_LLM_PREDECOMPOSE_V1,
|
||||
featureInvestigationStateV1: config_1.FEATURE_ASSISTANT_INVESTIGATION_STATE_V1,
|
||||
featureStateFollowupBindingV1: config_1.FEATURE_ASSISTANT_STATE_FOLLOWUP_BINDING_V1,
|
||||
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,
|
||||
defaultModel: config_1.DEFAULT_MODEL,
|
||||
defaultBaseUrl: config_1.DEFAULT_OPENAI_BASE_URL,
|
||||
compactWhitespace,
|
||||
repairAddressMojibake,
|
||||
resolveRuntimeAnalysisContext,
|
||||
runAddressLlmPreDecompose: async (runtimePayload, runtimeUserMessage) => runAddressLlmPreDecompose(this.normalizerService, runtimePayload, runtimeUserMessage),
|
||||
buildAddressLlmPredecomposeContractV1: predecomposeContract_1.buildAddressLlmPredecomposeContractV1,
|
||||
sanitizeAddressMessageForFallback,
|
||||
toNonEmptyString,
|
||||
resolveAddressFollowupCarryoverContext,
|
||||
resolveAssistantOrchestrationDecision,
|
||||
buildAddressDialogContinuationContractV2,
|
||||
mergeFollowupContextWithOrganizationScope,
|
||||
isRetryableAddressLimitedResult,
|
||||
mergeKnownOrganizations,
|
||||
hasAssistantDataScopeMetaQuestionSignal,
|
||||
shouldHandleAsAssistantCapabilityMetaQuery,
|
||||
hasDestructiveDataActionSignal,
|
||||
hasDangerOrCoercionSignal,
|
||||
hasOperationalAdminActionRequestSignal,
|
||||
hasOrganizationFactLookupSignal,
|
||||
hasOrganizationFactFollowupSignal,
|
||||
shouldEmitOrganizationSelectionReply,
|
||||
hasAssistantCapabilityQuestionSignal,
|
||||
resolveDataScopeProbe: () => resolveAssistantDataScopeProbe(),
|
||||
applyScriptGuard: (chatText, runtimeUserMessage) => applyLivingChatScriptGuard(chatText, runtimeUserMessage),
|
||||
applyGroundingGuard: (guardInput) => applyLivingChatGroundingGuard(guardInput),
|
||||
buildAssistantSafetyRefusalReply,
|
||||
buildAssistantDataScopeContractReply,
|
||||
buildAssistantOrganizationFactBoundaryReply,
|
||||
buildAssistantDataScopeSelectionReply,
|
||||
buildAssistantOperationalBoundaryReply,
|
||||
buildAssistantCapabilityContractReply,
|
||||
loadAssistantCanonExcerpt: assistantCanon_1.loadAssistantCanonExcerpt,
|
||||
sanitizeOutgoingAssistantText,
|
||||
buildAddressDebugPayload,
|
||||
buildAddressFollowupOffer,
|
||||
buildFollowupStateBinding,
|
||||
resolveBusinessScopeAlignment,
|
||||
inferP0DomainFromMessage,
|
||||
resolveBusinessScopeFromLiveContext,
|
||||
extractRequirements,
|
||||
toExecutionPlan,
|
||||
enforceRbpLiveRoutePlan,
|
||||
enforceFaLiveRoutePlan,
|
||||
mapNoRouteReason,
|
||||
buildSkippedResult,
|
||||
evaluateCoverage,
|
||||
checkGrounding,
|
||||
collectRbpLiveRouteAudit,
|
||||
collectFaLiveRouteAudit,
|
||||
hasExplicitPeriodAnchorFromNormalized,
|
||||
extractDroppedIntentSegments: (normalizedPayload) => extractDiscardedIntentSegments(normalizedPayload),
|
||||
toDebugRoutes: (routeSummary) => toDebugRoutes(routeSummary),
|
||||
extractExecutionState
|
||||
};
|
||||
flags: {
|
||||
featureAssistantAddressQueryV1: config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_V1,
|
||||
featureAddressLlmPredecomposeV1: config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_LLM_PREDECOMPOSE_V1,
|
||||
featureInvestigationStateV1: config_1.FEATURE_ASSISTANT_INVESTIGATION_STATE_V1,
|
||||
featureStateFollowupBindingV1: config_1.FEATURE_ASSISTANT_STATE_FOLLOWUP_BINDING_V1,
|
||||
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
|
||||
},
|
||||
defaults: {
|
||||
defaultModel: config_1.DEFAULT_MODEL,
|
||||
defaultBaseUrl: config_1.DEFAULT_OPENAI_BASE_URL
|
||||
},
|
||||
helpers: {
|
||||
compactWhitespace,
|
||||
repairAddressMojibake,
|
||||
resolveRuntimeAnalysisContext,
|
||||
runAddressLlmPreDecompose: async (runtimePayload, runtimeUserMessage) => runAddressLlmPreDecompose(this.normalizerService, runtimePayload, runtimeUserMessage),
|
||||
buildAddressLlmPredecomposeContractV1: predecomposeContract_1.buildAddressLlmPredecomposeContractV1,
|
||||
sanitizeAddressMessageForFallback,
|
||||
toNonEmptyString,
|
||||
resolveAddressFollowupCarryoverContext,
|
||||
resolveAssistantOrchestrationDecision,
|
||||
buildAddressDialogContinuationContractV2,
|
||||
mergeFollowupContextWithOrganizationScope,
|
||||
isRetryableAddressLimitedResult,
|
||||
mergeKnownOrganizations,
|
||||
hasAssistantDataScopeMetaQuestionSignal,
|
||||
shouldHandleAsAssistantCapabilityMetaQuery,
|
||||
hasDestructiveDataActionSignal,
|
||||
hasDangerOrCoercionSignal,
|
||||
hasOperationalAdminActionRequestSignal,
|
||||
hasOrganizationFactLookupSignal,
|
||||
hasOrganizationFactFollowupSignal,
|
||||
shouldEmitOrganizationSelectionReply,
|
||||
hasAssistantCapabilityQuestionSignal,
|
||||
resolveDataScopeProbe: () => resolveAssistantDataScopeProbe(),
|
||||
applyScriptGuard: (chatText, runtimeUserMessage) => applyLivingChatScriptGuard(chatText, runtimeUserMessage),
|
||||
applyGroundingGuard: (guardInput) => applyLivingChatGroundingGuard(guardInput),
|
||||
buildAssistantSafetyRefusalReply,
|
||||
buildAssistantDataScopeContractReply,
|
||||
buildAssistantOrganizationFactBoundaryReply,
|
||||
buildAssistantDataScopeSelectionReply,
|
||||
buildAssistantOperationalBoundaryReply,
|
||||
buildAssistantCapabilityContractReply,
|
||||
loadAssistantCanonExcerpt: assistantCanon_1.loadAssistantCanonExcerpt,
|
||||
sanitizeOutgoingAssistantText,
|
||||
buildAddressDebugPayload,
|
||||
buildAddressFollowupOffer,
|
||||
buildFollowupStateBinding,
|
||||
resolveBusinessScopeAlignment,
|
||||
inferP0DomainFromMessage,
|
||||
resolveBusinessScopeFromLiveContext,
|
||||
extractRequirements,
|
||||
toExecutionPlan,
|
||||
enforceRbpLiveRoutePlan,
|
||||
enforceFaLiveRoutePlan,
|
||||
mapNoRouteReason,
|
||||
buildSkippedResult,
|
||||
evaluateCoverage,
|
||||
checkGrounding,
|
||||
collectRbpLiveRouteAudit,
|
||||
collectFaLiveRouteAudit,
|
||||
hasExplicitPeriodAnchorFromNormalized,
|
||||
extractDroppedIntentSegments: (normalizedPayload) => extractDiscardedIntentSegments(normalizedPayload),
|
||||
toDebugRoutes: (routeSummary) => toDebugRoutes(routeSummary),
|
||||
extractExecutionState
|
||||
}
|
||||
});
|
||||
const turnRuntime = await (0, assistantTurnAttemptRuntimeAdapter_1.runAssistantTurnAttemptRuntime)({
|
||||
payload,
|
||||
runUserTurnBootstrapRuntime: (runtimePayload) => (0, assistantUserTurnBootstrapRuntimeAdapter_1.runAssistantUserTurnBootstrapRuntime)((0, assistantTurnRuntimeInputBuilder_1.buildAssistantUserTurnBootstrapRuntimeInput)(runtimePayload, turnRuntimeDeps)),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.buildAssistantTurnRuntimeDeps = buildAssistantTurnRuntimeDeps;
|
||||
function buildAssistantTurnRuntimeDeps(input) {
|
||||
return {
|
||||
...input.helpers,
|
||||
ensureSession: (sessionId) => input.sessions.ensureSession(sessionId),
|
||||
appendItem: (sessionId, item) => input.sessions.appendItem(sessionId, item),
|
||||
getSession: (sessionId) => input.sessions.getSession(sessionId),
|
||||
persistSession: (sessionState) => input.sessionLogger.persistSession(sessionState),
|
||||
setInvestigationState: (sessionId, snapshot) => input.sessions.setInvestigationState(sessionId, snapshot),
|
||||
normalize: (payload) => input.normalizerService.normalize(payload),
|
||||
executeRouteRuntime: (route, fragmentText, options) => input.dataLayer.executeRouteRuntime(route, fragmentText, options),
|
||||
tryAddressQueryHandle: (messageUsed, options) => input.addressQueryService.tryHandle(messageUsed, options),
|
||||
chatClient: input.chatClient,
|
||||
messageIdFactory: input.messageIdFactory,
|
||||
nowIso: input.nowIso,
|
||||
defaultApiKey: input.defaultApiKey,
|
||||
logEvent: input.logEvent,
|
||||
featureAssistantAddressQueryV1: input.flags.featureAssistantAddressQueryV1,
|
||||
featureAddressLlmPredecomposeV1: input.flags.featureAddressLlmPredecomposeV1,
|
||||
featureInvestigationStateV1: input.flags.featureInvestigationStateV1,
|
||||
featureStateFollowupBindingV1: input.flags.featureStateFollowupBindingV1,
|
||||
featureContractsV11: input.flags.featureContractsV11,
|
||||
featureAnswerPolicyV11: input.flags.featureAnswerPolicyV11,
|
||||
featureProblemCentricAnswerV1: input.flags.featureProblemCentricAnswerV1,
|
||||
featureLifecycleAnswerV1: input.flags.featureLifecycleAnswerV1,
|
||||
defaultModel: input.defaults.defaultModel,
|
||||
defaultBaseUrl: input.defaults.defaultBaseUrl
|
||||
};
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ import * as assistantAddressAttemptRuntimeAdapter_1 from "./assistantAddressAtte
|
|||
import * as assistantCoverageGrounding_1 from "./assistantCoverageGrounding";
|
||||
import * as assistantDeepTurnAttemptRuntimeAdapter_1 from "./assistantDeepTurnAttemptRuntimeAdapter";
|
||||
import * as assistantTurnAttemptRuntimeAdapter_1 from "./assistantTurnAttemptRuntimeAdapter";
|
||||
import * as assistantTurnRuntimeDepsAdapter_1 from "./assistantTurnRuntimeDepsAdapter";
|
||||
import * as assistantTurnRuntimeInputBuilder_1 from "./assistantTurnRuntimeInputBuilder";
|
||||
import * as assistantUserTurnBootstrapRuntimeAdapter_1 from "./assistantUserTurnBootstrapRuntimeAdapter";
|
||||
import * as assistantQueryPlanning_1 from "./assistantQueryPlanning";
|
||||
|
|
@ -4326,84 +4327,87 @@ export class AssistantService {
|
|||
return this.sessions.getSession(sessionId);
|
||||
}
|
||||
async handleMessage(payload) {
|
||||
const turnRuntimeDeps = {
|
||||
ensureSession: (targetSessionId) => this.sessions.ensureSession(targetSessionId),
|
||||
appendItem: (targetSessionId, item) => this.sessions.appendItem(targetSessionId, item),
|
||||
getSession: (targetSessionId) => this.sessions.getSession(targetSessionId),
|
||||
persistSession: (sessionState) => this.sessionLogger.persistSession(sessionState),
|
||||
setInvestigationState: (targetSessionId, snapshot) => this.sessions.setInvestigationState(targetSessionId, snapshot),
|
||||
normalize: (normalizePayload) => this.normalizerService.normalize(normalizePayload),
|
||||
executeRouteRuntime: (route, fragmentText, options) => this.dataLayer.executeRouteRuntime(route, fragmentText, options),
|
||||
tryAddressQueryHandle: (laneMessageUsed, options) => this.addressQueryService.tryHandle(laneMessageUsed, options),
|
||||
const turnRuntimeDeps = (0, assistantTurnRuntimeDepsAdapter_1.buildAssistantTurnRuntimeDeps)({
|
||||
sessions: this.sessions,
|
||||
sessionLogger: this.sessionLogger,
|
||||
normalizerService: this.normalizerService,
|
||||
dataLayer: this.dataLayer,
|
||||
addressQueryService: this.addressQueryService,
|
||||
chatClient: this.chatClient,
|
||||
messageIdFactory: () => `msg-${(0, nanoid_1.nanoid)(10)}`,
|
||||
nowIso: () => new Date().toISOString(),
|
||||
defaultApiKey: process.env.OPENAI_API_KEY ?? "",
|
||||
logEvent: (runtimePayload) => (0, log_1.logJson)(runtimePayload),
|
||||
featureAssistantAddressQueryV1: config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_V1,
|
||||
featureAddressLlmPredecomposeV1: config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_LLM_PREDECOMPOSE_V1,
|
||||
featureInvestigationStateV1: config_1.FEATURE_ASSISTANT_INVESTIGATION_STATE_V1,
|
||||
featureStateFollowupBindingV1: config_1.FEATURE_ASSISTANT_STATE_FOLLOWUP_BINDING_V1,
|
||||
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,
|
||||
defaultModel: config_1.DEFAULT_MODEL,
|
||||
defaultBaseUrl: config_1.DEFAULT_OPENAI_BASE_URL,
|
||||
compactWhitespace,
|
||||
repairAddressMojibake,
|
||||
resolveRuntimeAnalysisContext,
|
||||
runAddressLlmPreDecompose: async (runtimePayload, runtimeUserMessage) => runAddressLlmPreDecompose(this.normalizerService, runtimePayload, runtimeUserMessage),
|
||||
buildAddressLlmPredecomposeContractV1: predecomposeContract_1.buildAddressLlmPredecomposeContractV1,
|
||||
sanitizeAddressMessageForFallback,
|
||||
toNonEmptyString,
|
||||
resolveAddressFollowupCarryoverContext,
|
||||
resolveAssistantOrchestrationDecision,
|
||||
buildAddressDialogContinuationContractV2,
|
||||
mergeFollowupContextWithOrganizationScope,
|
||||
isRetryableAddressLimitedResult,
|
||||
mergeKnownOrganizations,
|
||||
hasAssistantDataScopeMetaQuestionSignal,
|
||||
shouldHandleAsAssistantCapabilityMetaQuery,
|
||||
hasDestructiveDataActionSignal,
|
||||
hasDangerOrCoercionSignal,
|
||||
hasOperationalAdminActionRequestSignal,
|
||||
hasOrganizationFactLookupSignal,
|
||||
hasOrganizationFactFollowupSignal,
|
||||
shouldEmitOrganizationSelectionReply,
|
||||
hasAssistantCapabilityQuestionSignal,
|
||||
resolveDataScopeProbe: () => resolveAssistantDataScopeProbe(),
|
||||
applyScriptGuard: (chatText, runtimeUserMessage) => applyLivingChatScriptGuard(chatText, runtimeUserMessage),
|
||||
applyGroundingGuard: (guardInput) => applyLivingChatGroundingGuard(guardInput),
|
||||
buildAssistantSafetyRefusalReply,
|
||||
buildAssistantDataScopeContractReply,
|
||||
buildAssistantOrganizationFactBoundaryReply,
|
||||
buildAssistantDataScopeSelectionReply,
|
||||
buildAssistantOperationalBoundaryReply,
|
||||
buildAssistantCapabilityContractReply,
|
||||
loadAssistantCanonExcerpt: assistantCanon_1.loadAssistantCanonExcerpt,
|
||||
sanitizeOutgoingAssistantText,
|
||||
buildAddressDebugPayload,
|
||||
buildAddressFollowupOffer,
|
||||
buildFollowupStateBinding,
|
||||
resolveBusinessScopeAlignment,
|
||||
inferP0DomainFromMessage,
|
||||
resolveBusinessScopeFromLiveContext,
|
||||
extractRequirements,
|
||||
toExecutionPlan,
|
||||
enforceRbpLiveRoutePlan,
|
||||
enforceFaLiveRoutePlan,
|
||||
mapNoRouteReason,
|
||||
buildSkippedResult,
|
||||
evaluateCoverage,
|
||||
checkGrounding,
|
||||
collectRbpLiveRouteAudit,
|
||||
collectFaLiveRouteAudit,
|
||||
hasExplicitPeriodAnchorFromNormalized,
|
||||
extractDroppedIntentSegments: (normalizedPayload) => extractDiscardedIntentSegments(normalizedPayload),
|
||||
toDebugRoutes: (routeSummary) => toDebugRoutes(routeSummary),
|
||||
extractExecutionState
|
||||
};
|
||||
flags: {
|
||||
featureAssistantAddressQueryV1: config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_V1,
|
||||
featureAddressLlmPredecomposeV1: config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_LLM_PREDECOMPOSE_V1,
|
||||
featureInvestigationStateV1: config_1.FEATURE_ASSISTANT_INVESTIGATION_STATE_V1,
|
||||
featureStateFollowupBindingV1: config_1.FEATURE_ASSISTANT_STATE_FOLLOWUP_BINDING_V1,
|
||||
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
|
||||
},
|
||||
defaults: {
|
||||
defaultModel: config_1.DEFAULT_MODEL,
|
||||
defaultBaseUrl: config_1.DEFAULT_OPENAI_BASE_URL
|
||||
},
|
||||
helpers: {
|
||||
compactWhitespace,
|
||||
repairAddressMojibake,
|
||||
resolveRuntimeAnalysisContext,
|
||||
runAddressLlmPreDecompose: async (runtimePayload, runtimeUserMessage) => runAddressLlmPreDecompose(this.normalizerService, runtimePayload, runtimeUserMessage),
|
||||
buildAddressLlmPredecomposeContractV1: predecomposeContract_1.buildAddressLlmPredecomposeContractV1,
|
||||
sanitizeAddressMessageForFallback,
|
||||
toNonEmptyString,
|
||||
resolveAddressFollowupCarryoverContext,
|
||||
resolveAssistantOrchestrationDecision,
|
||||
buildAddressDialogContinuationContractV2,
|
||||
mergeFollowupContextWithOrganizationScope,
|
||||
isRetryableAddressLimitedResult,
|
||||
mergeKnownOrganizations,
|
||||
hasAssistantDataScopeMetaQuestionSignal,
|
||||
shouldHandleAsAssistantCapabilityMetaQuery,
|
||||
hasDestructiveDataActionSignal,
|
||||
hasDangerOrCoercionSignal,
|
||||
hasOperationalAdminActionRequestSignal,
|
||||
hasOrganizationFactLookupSignal,
|
||||
hasOrganizationFactFollowupSignal,
|
||||
shouldEmitOrganizationSelectionReply,
|
||||
hasAssistantCapabilityQuestionSignal,
|
||||
resolveDataScopeProbe: () => resolveAssistantDataScopeProbe(),
|
||||
applyScriptGuard: (chatText, runtimeUserMessage) => applyLivingChatScriptGuard(chatText, runtimeUserMessage),
|
||||
applyGroundingGuard: (guardInput) => applyLivingChatGroundingGuard(guardInput),
|
||||
buildAssistantSafetyRefusalReply,
|
||||
buildAssistantDataScopeContractReply,
|
||||
buildAssistantOrganizationFactBoundaryReply,
|
||||
buildAssistantDataScopeSelectionReply,
|
||||
buildAssistantOperationalBoundaryReply,
|
||||
buildAssistantCapabilityContractReply,
|
||||
loadAssistantCanonExcerpt: assistantCanon_1.loadAssistantCanonExcerpt,
|
||||
sanitizeOutgoingAssistantText,
|
||||
buildAddressDebugPayload,
|
||||
buildAddressFollowupOffer,
|
||||
buildFollowupStateBinding,
|
||||
resolveBusinessScopeAlignment,
|
||||
inferP0DomainFromMessage,
|
||||
resolveBusinessScopeFromLiveContext,
|
||||
extractRequirements,
|
||||
toExecutionPlan,
|
||||
enforceRbpLiveRoutePlan,
|
||||
enforceFaLiveRoutePlan,
|
||||
mapNoRouteReason,
|
||||
buildSkippedResult,
|
||||
evaluateCoverage,
|
||||
checkGrounding,
|
||||
collectRbpLiveRouteAudit,
|
||||
collectFaLiveRouteAudit,
|
||||
hasExplicitPeriodAnchorFromNormalized,
|
||||
extractDroppedIntentSegments: (normalizedPayload) => extractDiscardedIntentSegments(normalizedPayload),
|
||||
toDebugRoutes: (routeSummary) => toDebugRoutes(routeSummary),
|
||||
extractExecutionState
|
||||
}
|
||||
});
|
||||
const turnRuntime = await (0, assistantTurnAttemptRuntimeAdapter_1.runAssistantTurnAttemptRuntime)({
|
||||
payload,
|
||||
runUserTurnBootstrapRuntime: (runtimePayload) => (0, assistantUserTurnBootstrapRuntimeAdapter_1.runAssistantUserTurnBootstrapRuntime)((0, assistantTurnRuntimeInputBuilder_1.buildAssistantUserTurnBootstrapRuntimeInput)(runtimePayload, turnRuntimeDeps)),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,112 @@
|
|||
import type { AssistantTurnRuntimeBuilderDeps } from "./assistantTurnRuntimeInputBuilder";
|
||||
|
||||
export interface AssistantTurnRuntimeDepsSessionsLike {
|
||||
ensureSession: (sessionId: string) => unknown;
|
||||
appendItem: (sessionId: string, item: unknown) => void;
|
||||
getSession: (sessionId: string) => unknown;
|
||||
setInvestigationState: (sessionId: string, snapshot: unknown) => void;
|
||||
}
|
||||
|
||||
export interface AssistantTurnRuntimeDepsSessionLoggerLike {
|
||||
persistSession: (sessionState: unknown) => void;
|
||||
}
|
||||
|
||||
export interface AssistantTurnRuntimeDepsNormalizerLike {
|
||||
normalize: (payload: unknown) => Promise<unknown>;
|
||||
}
|
||||
|
||||
export interface AssistantTurnRuntimeDepsDataLayerLike {
|
||||
executeRouteRuntime: (route: string, fragmentText: string, options?: unknown) => Promise<unknown>;
|
||||
}
|
||||
|
||||
export interface AssistantTurnRuntimeDepsAddressQueryServiceLike {
|
||||
tryHandle: (messageUsed: string, options?: unknown) => Promise<unknown>;
|
||||
}
|
||||
|
||||
type BuilderDepsProvidedByAdapter = Pick<
|
||||
AssistantTurnRuntimeBuilderDeps,
|
||||
| "ensureSession"
|
||||
| "appendItem"
|
||||
| "getSession"
|
||||
| "persistSession"
|
||||
| "setInvestigationState"
|
||||
| "normalize"
|
||||
| "executeRouteRuntime"
|
||||
| "tryAddressQueryHandle"
|
||||
| "chatClient"
|
||||
| "messageIdFactory"
|
||||
| "nowIso"
|
||||
| "defaultApiKey"
|
||||
| "logEvent"
|
||||
| "featureAssistantAddressQueryV1"
|
||||
| "featureAddressLlmPredecomposeV1"
|
||||
| "featureInvestigationStateV1"
|
||||
| "featureStateFollowupBindingV1"
|
||||
| "featureContractsV11"
|
||||
| "featureAnswerPolicyV11"
|
||||
| "featureProblemCentricAnswerV1"
|
||||
| "featureLifecycleAnswerV1"
|
||||
| "defaultModel"
|
||||
| "defaultBaseUrl"
|
||||
>;
|
||||
|
||||
type BuilderDepsPassThrough = Omit<AssistantTurnRuntimeBuilderDeps, keyof BuilderDepsProvidedByAdapter>;
|
||||
|
||||
export interface BuildAssistantTurnRuntimeDepsInput {
|
||||
sessions: AssistantTurnRuntimeDepsSessionsLike;
|
||||
sessionLogger: AssistantTurnRuntimeDepsSessionLoggerLike;
|
||||
normalizerService: AssistantTurnRuntimeDepsNormalizerLike;
|
||||
dataLayer: AssistantTurnRuntimeDepsDataLayerLike;
|
||||
addressQueryService: AssistantTurnRuntimeDepsAddressQueryServiceLike;
|
||||
chatClient: unknown;
|
||||
messageIdFactory: () => string;
|
||||
nowIso: () => string;
|
||||
defaultApiKey: string;
|
||||
logEvent: (payload: Record<string, unknown>) => void;
|
||||
flags: {
|
||||
featureAssistantAddressQueryV1: boolean;
|
||||
featureAddressLlmPredecomposeV1: boolean;
|
||||
featureInvestigationStateV1: boolean;
|
||||
featureStateFollowupBindingV1: boolean;
|
||||
featureContractsV11: boolean;
|
||||
featureAnswerPolicyV11: boolean;
|
||||
featureProblemCentricAnswerV1: boolean;
|
||||
featureLifecycleAnswerV1: boolean;
|
||||
};
|
||||
defaults: {
|
||||
defaultModel: string;
|
||||
defaultBaseUrl: string;
|
||||
};
|
||||
helpers: BuilderDepsPassThrough;
|
||||
}
|
||||
|
||||
export function buildAssistantTurnRuntimeDeps(
|
||||
input: BuildAssistantTurnRuntimeDepsInput
|
||||
): AssistantTurnRuntimeBuilderDeps {
|
||||
return {
|
||||
...input.helpers,
|
||||
ensureSession: (sessionId) => input.sessions.ensureSession(sessionId) as any,
|
||||
appendItem: (sessionId, item) => input.sessions.appendItem(sessionId, item as any),
|
||||
getSession: (sessionId) => input.sessions.getSession(sessionId) as any,
|
||||
persistSession: (sessionState) => input.sessionLogger.persistSession(sessionState as any),
|
||||
setInvestigationState: (sessionId, snapshot) => input.sessions.setInvestigationState(sessionId, snapshot),
|
||||
normalize: (payload) => input.normalizerService.normalize(payload),
|
||||
executeRouteRuntime: (route, fragmentText, options) => input.dataLayer.executeRouteRuntime(route, fragmentText, options),
|
||||
tryAddressQueryHandle: (messageUsed, options) => input.addressQueryService.tryHandle(messageUsed, options),
|
||||
chatClient: input.chatClient,
|
||||
messageIdFactory: input.messageIdFactory,
|
||||
nowIso: input.nowIso,
|
||||
defaultApiKey: input.defaultApiKey,
|
||||
logEvent: input.logEvent,
|
||||
featureAssistantAddressQueryV1: input.flags.featureAssistantAddressQueryV1,
|
||||
featureAddressLlmPredecomposeV1: input.flags.featureAddressLlmPredecomposeV1,
|
||||
featureInvestigationStateV1: input.flags.featureInvestigationStateV1,
|
||||
featureStateFollowupBindingV1: input.flags.featureStateFollowupBindingV1,
|
||||
featureContractsV11: input.flags.featureContractsV11,
|
||||
featureAnswerPolicyV11: input.flags.featureAnswerPolicyV11,
|
||||
featureProblemCentricAnswerV1: input.flags.featureProblemCentricAnswerV1,
|
||||
featureLifecycleAnswerV1: input.flags.featureLifecycleAnswerV1,
|
||||
defaultModel: input.defaults.defaultModel,
|
||||
defaultBaseUrl: input.defaults.defaultBaseUrl
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
import { describe, expect, it, vi } from "vitest";
|
||||
import { buildAssistantTurnRuntimeDeps } from "../src/services/assistantTurnRuntimeDepsAdapter";
|
||||
|
||||
describe("assistant turn runtime deps adapter", () => {
|
||||
it("builds runtime deps with service wrappers and static flags/defaults", async () => {
|
||||
const sessions = {
|
||||
ensureSession: vi.fn(() => ({ session_id: "asst-1" })),
|
||||
appendItem: vi.fn(),
|
||||
getSession: vi.fn(() => ({ session_id: "asst-1" })),
|
||||
setInvestigationState: vi.fn()
|
||||
};
|
||||
const sessionLogger = {
|
||||
persistSession: vi.fn()
|
||||
};
|
||||
const normalizerService = {
|
||||
normalize: vi.fn(async () => ({ trace_id: "trace-1" }))
|
||||
};
|
||||
const dataLayer = {
|
||||
executeRouteRuntime: vi.fn(async () => ({ status: "ok" }))
|
||||
};
|
||||
const addressQueryService = {
|
||||
tryHandle: vi.fn(async () => ({ response_type: "READY" }))
|
||||
};
|
||||
const logEvent = vi.fn();
|
||||
const helperFn = vi.fn(() => "ok");
|
||||
|
||||
const deps = buildAssistantTurnRuntimeDeps({
|
||||
sessions,
|
||||
sessionLogger,
|
||||
normalizerService,
|
||||
dataLayer,
|
||||
addressQueryService,
|
||||
chatClient: { kind: "chat" },
|
||||
messageIdFactory: () => "msg-1",
|
||||
nowIso: () => "2026-04-11T00:00:00.000Z",
|
||||
defaultApiKey: "api-key",
|
||||
logEvent,
|
||||
flags: {
|
||||
featureAssistantAddressQueryV1: true,
|
||||
featureAddressLlmPredecomposeV1: true,
|
||||
featureInvestigationStateV1: true,
|
||||
featureStateFollowupBindingV1: false,
|
||||
featureContractsV11: true,
|
||||
featureAnswerPolicyV11: true,
|
||||
featureProblemCentricAnswerV1: true,
|
||||
featureLifecycleAnswerV1: false
|
||||
},
|
||||
defaults: {
|
||||
defaultModel: "gpt-5",
|
||||
defaultBaseUrl: "http://localhost"
|
||||
},
|
||||
helpers: {
|
||||
compactWhitespace: helperFn
|
||||
} as any
|
||||
});
|
||||
|
||||
deps.ensureSession("asst-1");
|
||||
deps.appendItem("asst-1", { role: "assistant" } as any);
|
||||
deps.getSession("asst-1");
|
||||
deps.persistSession({ session_id: "asst-1" } as any);
|
||||
deps.setInvestigationState("asst-1", { scope: "x" });
|
||||
await deps.normalize({ user_message: "q" });
|
||||
await deps.executeRouteRuntime("store_canonical", "fragment");
|
||||
await deps.tryAddressQueryHandle("message", { analysisDateHint: "2020-07-31" });
|
||||
deps.logEvent({ event: "ok" });
|
||||
|
||||
expect(sessions.ensureSession).toHaveBeenCalledWith("asst-1");
|
||||
expect(sessions.appendItem).toHaveBeenCalledWith("asst-1", { role: "assistant" });
|
||||
expect(sessions.getSession).toHaveBeenCalledWith("asst-1");
|
||||
expect(sessionLogger.persistSession).toHaveBeenCalledWith({ session_id: "asst-1" });
|
||||
expect(sessions.setInvestigationState).toHaveBeenCalledWith("asst-1", { scope: "x" });
|
||||
expect(normalizerService.normalize).toHaveBeenCalledWith({ user_message: "q" });
|
||||
expect(dataLayer.executeRouteRuntime).toHaveBeenCalledWith("store_canonical", "fragment", undefined);
|
||||
expect(addressQueryService.tryHandle).toHaveBeenCalledWith("message", { analysisDateHint: "2020-07-31" });
|
||||
expect(logEvent).toHaveBeenCalledWith({ event: "ok" });
|
||||
expect(deps.featureContractsV11).toBe(true);
|
||||
expect(deps.featureLifecycleAnswerV1).toBe(false);
|
||||
expect(deps.defaultModel).toBe("gpt-5");
|
||||
expect(deps.defaultBaseUrl).toBe("http://localhost");
|
||||
expect(deps.defaultApiKey).toBe("api-key");
|
||||
});
|
||||
|
||||
it("preserves helper functions in merged deps payload", () => {
|
||||
const helperCompactWhitespace = vi.fn((value: unknown) => String(value ?? "").trim());
|
||||
|
||||
const deps = buildAssistantTurnRuntimeDeps({
|
||||
sessions: {
|
||||
ensureSession: () => null,
|
||||
appendItem: () => {},
|
||||
getSession: () => null,
|
||||
setInvestigationState: () => {}
|
||||
},
|
||||
sessionLogger: {
|
||||
persistSession: () => {}
|
||||
},
|
||||
normalizerService: {
|
||||
normalize: async () => ({})
|
||||
},
|
||||
dataLayer: {
|
||||
executeRouteRuntime: async () => ({})
|
||||
},
|
||||
addressQueryService: {
|
||||
tryHandle: async () => null
|
||||
},
|
||||
chatClient: {},
|
||||
messageIdFactory: () => "msg-2",
|
||||
nowIso: () => "2026-04-11T00:00:00.000Z",
|
||||
defaultApiKey: "",
|
||||
logEvent: () => {},
|
||||
flags: {
|
||||
featureAssistantAddressQueryV1: false,
|
||||
featureAddressLlmPredecomposeV1: false,
|
||||
featureInvestigationStateV1: false,
|
||||
featureStateFollowupBindingV1: false,
|
||||
featureContractsV11: false,
|
||||
featureAnswerPolicyV11: false,
|
||||
featureProblemCentricAnswerV1: false,
|
||||
featureLifecycleAnswerV1: false
|
||||
},
|
||||
defaults: {
|
||||
defaultModel: "model",
|
||||
defaultBaseUrl: "base"
|
||||
},
|
||||
helpers: {
|
||||
compactWhitespace: helperCompactWhitespace
|
||||
} as any
|
||||
});
|
||||
|
||||
expect(deps.compactWhitespace(" value ")).toBe("value");
|
||||
expect(helperCompactWhitespace).toHaveBeenCalledWith(" value ");
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue