ГЛОБАЛЬНЫЙ РЕФАКТОРИНГ АРХИТЕКТУРЫ - Рефакторинг этапов
This commit is contained in:
parent
90d529f79b
commit
f1e621fccc
|
|
@ -1501,7 +1501,43 @@ Validation:
|
||||||
- `assistantDeepTurnPackagingRuntimeAdapter.test.ts`
|
- `assistantDeepTurnPackagingRuntimeAdapter.test.ts`
|
||||||
- `assistantWave10SettlementCorrectiveRegression.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 completed)**
|
Implemented in current pass (Phase 2.48):
|
||||||
|
1. Extracted turn-level runtime input assembly from `assistantService` into dedicated builder module:
|
||||||
|
- `assistantTurnRuntimeInputBuilder.ts`
|
||||||
|
- introduced:
|
||||||
|
- `buildAssistantUserTurnBootstrapRuntimeInput(...)`
|
||||||
|
- `buildAssistantAddressAttemptRuntimeInput(...)`
|
||||||
|
- `buildAssistantDeepTurnAttemptRuntimeInput(...)`
|
||||||
|
2. Rewired `assistantService.handleMessage` to consume builder outputs (behavior-preserving):
|
||||||
|
- moved bulky dependency mapping for bootstrap/address/deep attempts out of service body;
|
||||||
|
- preserved existing runtime adapters and route behavior.
|
||||||
|
3. Added focused unit tests:
|
||||||
|
- `assistantTurnRuntimeInputBuilder.test.ts`
|
||||||
|
|
||||||
|
Validation:
|
||||||
|
1. `npm run build` passed.
|
||||||
|
2. Targeted living/address/deep followup pack passed:
|
||||||
|
- `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 completed)**
|
||||||
|
|
||||||
## Stage 3 (P2): Hybrid Semantic Layer (LLM + Deterministic Guards)
|
## 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 assistantCoverageGrounding_1 = __importStar(require("./assistantCoverageGrounding"));
|
||||||
const assistantDeepTurnAttemptRuntimeAdapter_1 = __importStar(require("./assistantDeepTurnAttemptRuntimeAdapter"));
|
const assistantDeepTurnAttemptRuntimeAdapter_1 = __importStar(require("./assistantDeepTurnAttemptRuntimeAdapter"));
|
||||||
const assistantTurnAttemptRuntimeAdapter_1 = __importStar(require("./assistantTurnAttemptRuntimeAdapter"));
|
const assistantTurnAttemptRuntimeAdapter_1 = __importStar(require("./assistantTurnAttemptRuntimeAdapter"));
|
||||||
|
const assistantTurnRuntimeInputBuilder_1 = __importStar(require("./assistantTurnRuntimeInputBuilder"));
|
||||||
const assistantUserTurnBootstrapRuntimeAdapter_1 = __importStar(require("./assistantUserTurnBootstrapRuntimeAdapter"));
|
const assistantUserTurnBootstrapRuntimeAdapter_1 = __importStar(require("./assistantUserTurnBootstrapRuntimeAdapter"));
|
||||||
const assistantQueryPlanning_1 = __importStar(require("./assistantQueryPlanning"));
|
const assistantQueryPlanning_1 = __importStar(require("./assistantQueryPlanning"));
|
||||||
const iconv_lite_1 = __importDefault(require("iconv-lite"));
|
const iconv_lite_1 = __importDefault(require("iconv-lite"));
|
||||||
|
|
@ -4370,123 +4371,90 @@ class AssistantService {
|
||||||
return this.sessions.getSession(sessionId);
|
return this.sessions.getSession(sessionId);
|
||||||
}
|
}
|
||||||
async handleMessage(payload) {
|
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),
|
||||||
|
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
|
||||||
|
};
|
||||||
const turnRuntime = await (0, assistantTurnAttemptRuntimeAdapter_1.runAssistantTurnAttemptRuntime)({
|
const turnRuntime = await (0, assistantTurnAttemptRuntimeAdapter_1.runAssistantTurnAttemptRuntime)({
|
||||||
payload,
|
payload,
|
||||||
runUserTurnBootstrapRuntime: (runtimePayload) => (0, assistantUserTurnBootstrapRuntimeAdapter_1.runAssistantUserTurnBootstrapRuntime)({
|
runUserTurnBootstrapRuntime: (runtimePayload) => (0, assistantUserTurnBootstrapRuntimeAdapter_1.runAssistantUserTurnBootstrapRuntime)((0, assistantTurnRuntimeInputBuilder_1.buildAssistantUserTurnBootstrapRuntimeInput)(runtimePayload, turnRuntimeDeps)),
|
||||||
payload: runtimePayload,
|
|
||||||
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),
|
|
||||||
compactWhitespace,
|
|
||||||
repairAddressMojibake,
|
|
||||||
resolveRuntimeAnalysisContext,
|
|
||||||
messageIdFactory: () => `msg-${(0, nanoid_1.nanoid)(10)}`,
|
|
||||||
nowIso: () => new Date().toISOString()
|
|
||||||
}),
|
|
||||||
resolveSessionOrganizationScopeContext: (runtimeUserMessage, sessionItems) => resolveSessionOrganizationScopeContext(runtimeUserMessage, sessionItems),
|
resolveSessionOrganizationScopeContext: (runtimeUserMessage, sessionItems) => resolveSessionOrganizationScopeContext(runtimeUserMessage, sessionItems),
|
||||||
runAddressAttemptRuntime: async (runtimeInput) => (0, assistantAddressAttemptRuntimeAdapter_1.runAssistantAddressAttemptRuntime)({
|
runAddressAttemptRuntime: async (runtimeInput) => (0, assistantAddressAttemptRuntimeAdapter_1.runAssistantAddressAttemptRuntime)((0, assistantTurnRuntimeInputBuilder_1.buildAssistantAddressAttemptRuntimeInput)(runtimeInput, turnRuntimeDeps)),
|
||||||
featureAssistantAddressQueryV1: config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_V1,
|
runDeepTurnAttemptRuntime: async (runtimeInput) => (0, assistantDeepTurnAttemptRuntimeAdapter_1.runAssistantDeepTurnAttemptRuntime)((0, assistantTurnRuntimeInputBuilder_1.buildAssistantDeepTurnAttemptRuntimeInput)(runtimeInput, turnRuntimeDeps))
|
||||||
sessionId: runtimeInput.sessionId,
|
|
||||||
userMessage: runtimeInput.userMessage,
|
|
||||||
sessionItems: runtimeInput.sessionItems,
|
|
||||||
payload: runtimeInput.payload,
|
|
||||||
sessionScope: {
|
|
||||||
knownOrganizations: runtimeInput.sessionOrganizationScope.knownOrganizations,
|
|
||||||
selectedOrganization: runtimeInput.sessionOrganizationScope.selectedOrganization,
|
|
||||||
activeOrganization: runtimeInput.sessionOrganizationScope.activeOrganization
|
|
||||||
},
|
|
||||||
featureAddressLlmPredecomposeV1: config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_LLM_PREDECOMPOSE_V1,
|
|
||||||
runAddressLlmPreDecompose: async () => runAddressLlmPreDecompose(this.normalizerService, runtimeInput.payload, runtimeInput.userMessage),
|
|
||||||
buildAddressLlmPredecomposeContractV1: predecomposeContract_1.buildAddressLlmPredecomposeContractV1,
|
|
||||||
sanitizeAddressMessageForFallback,
|
|
||||||
toNonEmptyString,
|
|
||||||
resolveAddressFollowupCarryoverContext,
|
|
||||||
resolveAssistantOrchestrationDecision,
|
|
||||||
buildAddressDialogContinuationContractV2,
|
|
||||||
runtimeAnalysisContextAsOfDate: runtimeInput.runtimeAnalysisContext.as_of_date,
|
|
||||||
compactWhitespace,
|
|
||||||
mergeFollowupContextWithOrganizationScope,
|
|
||||||
runAddressQueryTryHandle: (laneMessageUsed, options) => this.addressQueryService.tryHandle(laneMessageUsed, options),
|
|
||||||
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,
|
|
||||||
chatClient: this.chatClient,
|
|
||||||
loadAssistantCanonExcerpt: assistantCanon_1.loadAssistantCanonExcerpt,
|
|
||||||
sanitizeOutgoingAssistantText,
|
|
||||||
defaultModel: config_1.DEFAULT_MODEL,
|
|
||||||
defaultBaseUrl: config_1.DEFAULT_OPENAI_BASE_URL,
|
|
||||||
defaultApiKey: process.env.OPENAI_API_KEY ?? "",
|
|
||||||
buildAddressDebugPayload,
|
|
||||||
buildAddressFollowupOffer,
|
|
||||||
appendItem: (targetSessionId, item) => this.sessions.appendItem(targetSessionId, item),
|
|
||||||
getSession: (targetSessionId) => this.sessions.getSession(targetSessionId),
|
|
||||||
persistSession: (sessionState) => this.sessionLogger.persistSession(sessionState),
|
|
||||||
cloneConversation: (items) => cloneItems(items),
|
|
||||||
logEvent: (runtimePayload) => (0, log_1.logJson)(runtimePayload),
|
|
||||||
messageIdFactory: () => `msg-${(0, nanoid_1.nanoid)(10)}`,
|
|
||||||
nowIso: () => new Date().toISOString()
|
|
||||||
}),
|
|
||||||
runDeepTurnAttemptRuntime: async (runtimeInput) => (0, assistantDeepTurnAttemptRuntimeAdapter_1.runAssistantDeepTurnAttemptRuntime)({
|
|
||||||
sessionId: runtimeInput.sessionId,
|
|
||||||
questionId: runtimeInput.questionId,
|
|
||||||
userMessage: runtimeInput.userMessage,
|
|
||||||
payload: runtimeInput.payload,
|
|
||||||
runtimeAnalysisContext: runtimeInput.runtimeAnalysisContext,
|
|
||||||
sessionInvestigationState: runtimeInput.sessionInvestigationState,
|
|
||||||
addressRuntimeMetaForDeep: runtimeInput.addressRuntimeMetaForDeep,
|
|
||||||
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,
|
|
||||||
buildFollowupStateBinding,
|
|
||||||
normalize: (normalizePayload) => this.normalizerService.normalize(normalizePayload),
|
|
||||||
resolveBusinessScopeAlignment,
|
|
||||||
inferP0DomainFromMessage,
|
|
||||||
resolveBusinessScopeFromLiveContext,
|
|
||||||
extractRequirements,
|
|
||||||
toExecutionPlan,
|
|
||||||
enforceRbpLiveRoutePlan,
|
|
||||||
enforceFaLiveRoutePlan,
|
|
||||||
executeRouteRuntime: (route, fragmentText, options) => this.dataLayer.executeRouteRuntime(route, fragmentText, options),
|
|
||||||
mapNoRouteReason,
|
|
||||||
buildSkippedResult,
|
|
||||||
evaluateCoverage,
|
|
||||||
checkGrounding,
|
|
||||||
collectRbpLiveRouteAudit,
|
|
||||||
collectFaLiveRouteAudit,
|
|
||||||
hasExplicitPeriodAnchor: (normalizedPayload) => hasExplicitPeriodAnchorFromNormalized(normalizedPayload),
|
|
||||||
extractDroppedIntentSegments: (normalizedPayload) => extractDiscardedIntentSegments(normalizedPayload),
|
|
||||||
buildDebugRoutes: (routeSummary) => toDebugRoutes(routeSummary),
|
|
||||||
extractExecutionState: (normalizedPayload) => extractExecutionState(normalizedPayload),
|
|
||||||
sanitizeReply: (value, fallback) => sanitizeOutgoingAssistantText(value, fallback),
|
|
||||||
persistInvestigationState: (targetSessionId, snapshot) => this.sessions.setInvestigationState(targetSessionId, snapshot),
|
|
||||||
messageIdFactory: () => `msg-${(0, nanoid_1.nanoid)(10)}`,
|
|
||||||
appendItem: (targetSessionId, item) => this.sessions.appendItem(targetSessionId, item),
|
|
||||||
getSession: (targetSessionId) => this.sessions.getSession(targetSessionId),
|
|
||||||
persistSession: (sessionState) => this.sessionLogger.persistSession(sessionState),
|
|
||||||
cloneConversation: (items) => cloneItems(items),
|
|
||||||
logEvent: (runtimePayload) => (0, log_1.logJson)(runtimePayload)
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
return turnRuntime.response;
|
return turnRuntime.response;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,125 @@
|
||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.buildAssistantUserTurnBootstrapRuntimeInput = buildAssistantUserTurnBootstrapRuntimeInput;
|
||||||
|
exports.buildAssistantAddressAttemptRuntimeInput = buildAssistantAddressAttemptRuntimeInput;
|
||||||
|
exports.buildAssistantDeepTurnAttemptRuntimeInput = buildAssistantDeepTurnAttemptRuntimeInput;
|
||||||
|
function buildAssistantUserTurnBootstrapRuntimeInput(payload, deps) {
|
||||||
|
return {
|
||||||
|
payload,
|
||||||
|
ensureSession: deps.ensureSession,
|
||||||
|
appendItem: deps.appendItem,
|
||||||
|
getSession: deps.getSession,
|
||||||
|
persistSession: deps.persistSession,
|
||||||
|
compactWhitespace: deps.compactWhitespace,
|
||||||
|
repairAddressMojibake: deps.repairAddressMojibake,
|
||||||
|
resolveRuntimeAnalysisContext: deps.resolveRuntimeAnalysisContext,
|
||||||
|
messageIdFactory: deps.messageIdFactory,
|
||||||
|
nowIso: deps.nowIso
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function buildAssistantAddressAttemptRuntimeInput(runtimeInput, deps) {
|
||||||
|
return {
|
||||||
|
featureAssistantAddressQueryV1: deps.featureAssistantAddressQueryV1,
|
||||||
|
sessionId: runtimeInput.sessionId,
|
||||||
|
userMessage: runtimeInput.userMessage,
|
||||||
|
sessionItems: runtimeInput.sessionItems,
|
||||||
|
payload: runtimeInput.payload,
|
||||||
|
sessionScope: {
|
||||||
|
knownOrganizations: runtimeInput.sessionOrganizationScope.knownOrganizations,
|
||||||
|
selectedOrganization: runtimeInput.sessionOrganizationScope.selectedOrganization,
|
||||||
|
activeOrganization: runtimeInput.sessionOrganizationScope.activeOrganization
|
||||||
|
},
|
||||||
|
featureAddressLlmPredecomposeV1: deps.featureAddressLlmPredecomposeV1,
|
||||||
|
runAddressLlmPreDecompose: async () => deps.runAddressLlmPreDecompose(runtimeInput.payload, runtimeInput.userMessage),
|
||||||
|
buildAddressLlmPredecomposeContractV1: deps.buildAddressLlmPredecomposeContractV1,
|
||||||
|
sanitizeAddressMessageForFallback: deps.sanitizeAddressMessageForFallback,
|
||||||
|
toNonEmptyString: deps.toNonEmptyString,
|
||||||
|
resolveAddressFollowupCarryoverContext: deps.resolveAddressFollowupCarryoverContext,
|
||||||
|
resolveAssistantOrchestrationDecision: deps.resolveAssistantOrchestrationDecision,
|
||||||
|
buildAddressDialogContinuationContractV2: deps.buildAddressDialogContinuationContractV2,
|
||||||
|
runtimeAnalysisContextAsOfDate: runtimeInput.runtimeAnalysisContext.as_of_date,
|
||||||
|
compactWhitespace: deps.compactWhitespace,
|
||||||
|
mergeFollowupContextWithOrganizationScope: deps.mergeFollowupContextWithOrganizationScope,
|
||||||
|
runAddressQueryTryHandle: deps.tryAddressQueryHandle,
|
||||||
|
isRetryableAddressLimitedResult: deps.isRetryableAddressLimitedResult,
|
||||||
|
mergeKnownOrganizations: deps.mergeKnownOrganizations,
|
||||||
|
hasAssistantDataScopeMetaQuestionSignal: deps.hasAssistantDataScopeMetaQuestionSignal,
|
||||||
|
shouldHandleAsAssistantCapabilityMetaQuery: deps.shouldHandleAsAssistantCapabilityMetaQuery,
|
||||||
|
hasDestructiveDataActionSignal: deps.hasDestructiveDataActionSignal,
|
||||||
|
hasDangerOrCoercionSignal: deps.hasDangerOrCoercionSignal,
|
||||||
|
hasOperationalAdminActionRequestSignal: deps.hasOperationalAdminActionRequestSignal,
|
||||||
|
hasOrganizationFactLookupSignal: deps.hasOrganizationFactLookupSignal,
|
||||||
|
hasOrganizationFactFollowupSignal: deps.hasOrganizationFactFollowupSignal,
|
||||||
|
shouldEmitOrganizationSelectionReply: deps.shouldEmitOrganizationSelectionReply,
|
||||||
|
hasAssistantCapabilityQuestionSignal: deps.hasAssistantCapabilityQuestionSignal,
|
||||||
|
resolveDataScopeProbe: deps.resolveDataScopeProbe,
|
||||||
|
applyScriptGuard: deps.applyScriptGuard,
|
||||||
|
applyGroundingGuard: deps.applyGroundingGuard,
|
||||||
|
buildAssistantSafetyRefusalReply: deps.buildAssistantSafetyRefusalReply,
|
||||||
|
buildAssistantDataScopeContractReply: deps.buildAssistantDataScopeContractReply,
|
||||||
|
buildAssistantOrganizationFactBoundaryReply: deps.buildAssistantOrganizationFactBoundaryReply,
|
||||||
|
buildAssistantDataScopeSelectionReply: deps.buildAssistantDataScopeSelectionReply,
|
||||||
|
buildAssistantOperationalBoundaryReply: deps.buildAssistantOperationalBoundaryReply,
|
||||||
|
buildAssistantCapabilityContractReply: deps.buildAssistantCapabilityContractReply,
|
||||||
|
chatClient: deps.chatClient,
|
||||||
|
loadAssistantCanonExcerpt: deps.loadAssistantCanonExcerpt,
|
||||||
|
sanitizeOutgoingAssistantText: deps.sanitizeOutgoingAssistantText,
|
||||||
|
defaultModel: deps.defaultModel,
|
||||||
|
defaultBaseUrl: deps.defaultBaseUrl,
|
||||||
|
defaultApiKey: deps.defaultApiKey,
|
||||||
|
buildAddressDebugPayload: deps.buildAddressDebugPayload,
|
||||||
|
buildAddressFollowupOffer: deps.buildAddressFollowupOffer,
|
||||||
|
appendItem: deps.appendItem,
|
||||||
|
getSession: deps.getSession,
|
||||||
|
persistSession: deps.persistSession,
|
||||||
|
cloneConversation: (items) => items.map((item) => ({ ...item })),
|
||||||
|
logEvent: deps.logEvent,
|
||||||
|
messageIdFactory: deps.messageIdFactory,
|
||||||
|
nowIso: deps.nowIso
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function buildAssistantDeepTurnAttemptRuntimeInput(runtimeInput, deps) {
|
||||||
|
return {
|
||||||
|
sessionId: runtimeInput.sessionId,
|
||||||
|
questionId: runtimeInput.questionId,
|
||||||
|
userMessage: runtimeInput.userMessage,
|
||||||
|
payload: runtimeInput.payload,
|
||||||
|
runtimeAnalysisContext: runtimeInput.runtimeAnalysisContext,
|
||||||
|
sessionInvestigationState: runtimeInput.sessionInvestigationState,
|
||||||
|
addressRuntimeMetaForDeep: runtimeInput.addressRuntimeMetaForDeep,
|
||||||
|
featureInvestigationStateV1: deps.featureInvestigationStateV1,
|
||||||
|
featureStateFollowupBindingV1: deps.featureStateFollowupBindingV1,
|
||||||
|
featureContractsV11: deps.featureContractsV11,
|
||||||
|
featureAnswerPolicyV11: deps.featureAnswerPolicyV11,
|
||||||
|
featureProblemCentricAnswerV1: deps.featureProblemCentricAnswerV1,
|
||||||
|
featureLifecycleAnswerV1: deps.featureLifecycleAnswerV1,
|
||||||
|
buildFollowupStateBinding: deps.buildFollowupStateBinding,
|
||||||
|
normalize: deps.normalize,
|
||||||
|
resolveBusinessScopeAlignment: deps.resolveBusinessScopeAlignment,
|
||||||
|
inferP0DomainFromMessage: deps.inferP0DomainFromMessage,
|
||||||
|
resolveBusinessScopeFromLiveContext: deps.resolveBusinessScopeFromLiveContext,
|
||||||
|
extractRequirements: deps.extractRequirements,
|
||||||
|
toExecutionPlan: deps.toExecutionPlan,
|
||||||
|
enforceRbpLiveRoutePlan: deps.enforceRbpLiveRoutePlan,
|
||||||
|
enforceFaLiveRoutePlan: deps.enforceFaLiveRoutePlan,
|
||||||
|
executeRouteRuntime: deps.executeRouteRuntime,
|
||||||
|
mapNoRouteReason: deps.mapNoRouteReason,
|
||||||
|
buildSkippedResult: deps.buildSkippedResult,
|
||||||
|
evaluateCoverage: deps.evaluateCoverage,
|
||||||
|
checkGrounding: deps.checkGrounding,
|
||||||
|
collectRbpLiveRouteAudit: deps.collectRbpLiveRouteAudit,
|
||||||
|
collectFaLiveRouteAudit: deps.collectFaLiveRouteAudit,
|
||||||
|
hasExplicitPeriodAnchor: deps.hasExplicitPeriodAnchorFromNormalized,
|
||||||
|
extractDroppedIntentSegments: deps.extractDroppedIntentSegments,
|
||||||
|
buildDebugRoutes: deps.toDebugRoutes,
|
||||||
|
extractExecutionState: deps.extractExecutionState,
|
||||||
|
sanitizeReply: deps.sanitizeOutgoingAssistantText,
|
||||||
|
persistInvestigationState: deps.setInvestigationState,
|
||||||
|
messageIdFactory: deps.messageIdFactory,
|
||||||
|
appendItem: deps.appendItem,
|
||||||
|
getSession: deps.getSession,
|
||||||
|
persistSession: deps.persistSession,
|
||||||
|
cloneConversation: (items) => items.map((item) => ({ ...item })),
|
||||||
|
logEvent: deps.logEvent
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -20,6 +20,7 @@ import * as assistantAddressAttemptRuntimeAdapter_1 from "./assistantAddressAtte
|
||||||
import * as assistantCoverageGrounding_1 from "./assistantCoverageGrounding";
|
import * as assistantCoverageGrounding_1 from "./assistantCoverageGrounding";
|
||||||
import * as assistantDeepTurnAttemptRuntimeAdapter_1 from "./assistantDeepTurnAttemptRuntimeAdapter";
|
import * as assistantDeepTurnAttemptRuntimeAdapter_1 from "./assistantDeepTurnAttemptRuntimeAdapter";
|
||||||
import * as assistantTurnAttemptRuntimeAdapter_1 from "./assistantTurnAttemptRuntimeAdapter";
|
import * as assistantTurnAttemptRuntimeAdapter_1 from "./assistantTurnAttemptRuntimeAdapter";
|
||||||
|
import * as assistantTurnRuntimeInputBuilder_1 from "./assistantTurnRuntimeInputBuilder";
|
||||||
import * as assistantUserTurnBootstrapRuntimeAdapter_1 from "./assistantUserTurnBootstrapRuntimeAdapter";
|
import * as assistantUserTurnBootstrapRuntimeAdapter_1 from "./assistantUserTurnBootstrapRuntimeAdapter";
|
||||||
import * as assistantQueryPlanning_1 from "./assistantQueryPlanning";
|
import * as assistantQueryPlanning_1 from "./assistantQueryPlanning";
|
||||||
import iconv from "iconv-lite";
|
import iconv from "iconv-lite";
|
||||||
|
|
@ -4325,123 +4326,90 @@ export class AssistantService {
|
||||||
return this.sessions.getSession(sessionId);
|
return this.sessions.getSession(sessionId);
|
||||||
}
|
}
|
||||||
async handleMessage(payload) {
|
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),
|
||||||
|
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
|
||||||
|
};
|
||||||
const turnRuntime = await (0, assistantTurnAttemptRuntimeAdapter_1.runAssistantTurnAttemptRuntime)({
|
const turnRuntime = await (0, assistantTurnAttemptRuntimeAdapter_1.runAssistantTurnAttemptRuntime)({
|
||||||
payload,
|
payload,
|
||||||
runUserTurnBootstrapRuntime: (runtimePayload) => (0, assistantUserTurnBootstrapRuntimeAdapter_1.runAssistantUserTurnBootstrapRuntime)({
|
runUserTurnBootstrapRuntime: (runtimePayload) => (0, assistantUserTurnBootstrapRuntimeAdapter_1.runAssistantUserTurnBootstrapRuntime)((0, assistantTurnRuntimeInputBuilder_1.buildAssistantUserTurnBootstrapRuntimeInput)(runtimePayload, turnRuntimeDeps)),
|
||||||
payload: runtimePayload,
|
|
||||||
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),
|
|
||||||
compactWhitespace,
|
|
||||||
repairAddressMojibake,
|
|
||||||
resolveRuntimeAnalysisContext,
|
|
||||||
messageIdFactory: () => `msg-${(0, nanoid_1.nanoid)(10)}`,
|
|
||||||
nowIso: () => new Date().toISOString()
|
|
||||||
}),
|
|
||||||
resolveSessionOrganizationScopeContext: (runtimeUserMessage, sessionItems) => resolveSessionOrganizationScopeContext(runtimeUserMessage, sessionItems),
|
resolveSessionOrganizationScopeContext: (runtimeUserMessage, sessionItems) => resolveSessionOrganizationScopeContext(runtimeUserMessage, sessionItems),
|
||||||
runAddressAttemptRuntime: async (runtimeInput) => (0, assistantAddressAttemptRuntimeAdapter_1.runAssistantAddressAttemptRuntime)({
|
runAddressAttemptRuntime: async (runtimeInput) => (0, assistantAddressAttemptRuntimeAdapter_1.runAssistantAddressAttemptRuntime)((0, assistantTurnRuntimeInputBuilder_1.buildAssistantAddressAttemptRuntimeInput)(runtimeInput, turnRuntimeDeps)),
|
||||||
featureAssistantAddressQueryV1: config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_V1,
|
runDeepTurnAttemptRuntime: async (runtimeInput) => (0, assistantDeepTurnAttemptRuntimeAdapter_1.runAssistantDeepTurnAttemptRuntime)((0, assistantTurnRuntimeInputBuilder_1.buildAssistantDeepTurnAttemptRuntimeInput)(runtimeInput, turnRuntimeDeps))
|
||||||
sessionId: runtimeInput.sessionId,
|
|
||||||
userMessage: runtimeInput.userMessage,
|
|
||||||
sessionItems: runtimeInput.sessionItems,
|
|
||||||
payload: runtimeInput.payload,
|
|
||||||
sessionScope: {
|
|
||||||
knownOrganizations: runtimeInput.sessionOrganizationScope.knownOrganizations,
|
|
||||||
selectedOrganization: runtimeInput.sessionOrganizationScope.selectedOrganization,
|
|
||||||
activeOrganization: runtimeInput.sessionOrganizationScope.activeOrganization
|
|
||||||
},
|
|
||||||
featureAddressLlmPredecomposeV1: config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_LLM_PREDECOMPOSE_V1,
|
|
||||||
runAddressLlmPreDecompose: async () => runAddressLlmPreDecompose(this.normalizerService, runtimeInput.payload, runtimeInput.userMessage),
|
|
||||||
buildAddressLlmPredecomposeContractV1: predecomposeContract_1.buildAddressLlmPredecomposeContractV1,
|
|
||||||
sanitizeAddressMessageForFallback,
|
|
||||||
toNonEmptyString,
|
|
||||||
resolveAddressFollowupCarryoverContext,
|
|
||||||
resolveAssistantOrchestrationDecision,
|
|
||||||
buildAddressDialogContinuationContractV2,
|
|
||||||
runtimeAnalysisContextAsOfDate: runtimeInput.runtimeAnalysisContext.as_of_date,
|
|
||||||
compactWhitespace,
|
|
||||||
mergeFollowupContextWithOrganizationScope,
|
|
||||||
runAddressQueryTryHandle: (laneMessageUsed, options) => this.addressQueryService.tryHandle(laneMessageUsed, options),
|
|
||||||
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,
|
|
||||||
chatClient: this.chatClient,
|
|
||||||
loadAssistantCanonExcerpt: assistantCanon_1.loadAssistantCanonExcerpt,
|
|
||||||
sanitizeOutgoingAssistantText,
|
|
||||||
defaultModel: config_1.DEFAULT_MODEL,
|
|
||||||
defaultBaseUrl: config_1.DEFAULT_OPENAI_BASE_URL,
|
|
||||||
defaultApiKey: process.env.OPENAI_API_KEY ?? "",
|
|
||||||
buildAddressDebugPayload,
|
|
||||||
buildAddressFollowupOffer,
|
|
||||||
appendItem: (targetSessionId, item) => this.sessions.appendItem(targetSessionId, item),
|
|
||||||
getSession: (targetSessionId) => this.sessions.getSession(targetSessionId),
|
|
||||||
persistSession: (sessionState) => this.sessionLogger.persistSession(sessionState),
|
|
||||||
cloneConversation: (items) => cloneItems(items),
|
|
||||||
logEvent: (runtimePayload) => (0, log_1.logJson)(runtimePayload),
|
|
||||||
messageIdFactory: () => `msg-${(0, nanoid_1.nanoid)(10)}`,
|
|
||||||
nowIso: () => new Date().toISOString()
|
|
||||||
}),
|
|
||||||
runDeepTurnAttemptRuntime: async (runtimeInput) => (0, assistantDeepTurnAttemptRuntimeAdapter_1.runAssistantDeepTurnAttemptRuntime)({
|
|
||||||
sessionId: runtimeInput.sessionId,
|
|
||||||
questionId: runtimeInput.questionId,
|
|
||||||
userMessage: runtimeInput.userMessage,
|
|
||||||
payload: runtimeInput.payload,
|
|
||||||
runtimeAnalysisContext: runtimeInput.runtimeAnalysisContext,
|
|
||||||
sessionInvestigationState: runtimeInput.sessionInvestigationState,
|
|
||||||
addressRuntimeMetaForDeep: runtimeInput.addressRuntimeMetaForDeep,
|
|
||||||
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,
|
|
||||||
buildFollowupStateBinding,
|
|
||||||
normalize: (normalizePayload) => this.normalizerService.normalize(normalizePayload),
|
|
||||||
resolveBusinessScopeAlignment,
|
|
||||||
inferP0DomainFromMessage,
|
|
||||||
resolveBusinessScopeFromLiveContext,
|
|
||||||
extractRequirements,
|
|
||||||
toExecutionPlan,
|
|
||||||
enforceRbpLiveRoutePlan,
|
|
||||||
enforceFaLiveRoutePlan,
|
|
||||||
executeRouteRuntime: (route, fragmentText, options) => this.dataLayer.executeRouteRuntime(route, fragmentText, options),
|
|
||||||
mapNoRouteReason,
|
|
||||||
buildSkippedResult,
|
|
||||||
evaluateCoverage,
|
|
||||||
checkGrounding,
|
|
||||||
collectRbpLiveRouteAudit,
|
|
||||||
collectFaLiveRouteAudit,
|
|
||||||
hasExplicitPeriodAnchor: (normalizedPayload) => hasExplicitPeriodAnchorFromNormalized(normalizedPayload),
|
|
||||||
extractDroppedIntentSegments: (normalizedPayload) => extractDiscardedIntentSegments(normalizedPayload),
|
|
||||||
buildDebugRoutes: (routeSummary) => toDebugRoutes(routeSummary),
|
|
||||||
extractExecutionState: (normalizedPayload) => extractExecutionState(normalizedPayload),
|
|
||||||
sanitizeReply: (value, fallback) => sanitizeOutgoingAssistantText(value, fallback),
|
|
||||||
persistInvestigationState: (targetSessionId, snapshot) => this.sessions.setInvestigationState(targetSessionId, snapshot),
|
|
||||||
messageIdFactory: () => `msg-${(0, nanoid_1.nanoid)(10)}`,
|
|
||||||
appendItem: (targetSessionId, item) => this.sessions.appendItem(targetSessionId, item),
|
|
||||||
getSession: (targetSessionId) => this.sessions.getSession(targetSessionId),
|
|
||||||
persistSession: (sessionState) => this.sessionLogger.persistSession(sessionState),
|
|
||||||
cloneConversation: (items) => cloneItems(items),
|
|
||||||
logEvent: (runtimePayload) => (0, log_1.logJson)(runtimePayload)
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
return turnRuntime.response;
|
return turnRuntime.response;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,221 @@
|
||||||
|
import type { RunAssistantAddressAttemptRuntimeInput } from "./assistantAddressAttemptRuntimeAdapter";
|
||||||
|
import type { RunAssistantDeepTurnAttemptRuntimeInput } from "./assistantDeepTurnAttemptRuntimeAdapter";
|
||||||
|
import type {
|
||||||
|
RunAssistantTurnAttemptRuntimeAddressInput,
|
||||||
|
RunAssistantTurnAttemptRuntimeDeepInput
|
||||||
|
} from "./assistantTurnAttemptRuntimeAdapter";
|
||||||
|
import type {
|
||||||
|
AssistantUserTurnBootstrapPayloadLike,
|
||||||
|
RunAssistantUserTurnBootstrapRuntimeInput
|
||||||
|
} from "./assistantUserTurnBootstrapRuntimeAdapter";
|
||||||
|
|
||||||
|
export interface AssistantTurnRuntimeBuilderDeps {
|
||||||
|
ensureSession: RunAssistantUserTurnBootstrapRuntimeInput["ensureSession"];
|
||||||
|
appendItem: RunAssistantUserTurnBootstrapRuntimeInput["appendItem"];
|
||||||
|
getSession: RunAssistantUserTurnBootstrapRuntimeInput["getSession"];
|
||||||
|
persistSession: RunAssistantUserTurnBootstrapRuntimeInput["persistSession"];
|
||||||
|
setInvestigationState: (sessionId: string, snapshot: unknown) => void;
|
||||||
|
normalize: (payload: unknown) => Promise<unknown>;
|
||||||
|
executeRouteRuntime: (route: string, fragmentText: string, options?: unknown) => Promise<unknown>;
|
||||||
|
tryAddressQueryHandle: (messageUsed: string, options?: unknown) => Promise<unknown>;
|
||||||
|
chatClient: unknown;
|
||||||
|
messageIdFactory: () => string;
|
||||||
|
nowIso: () => string;
|
||||||
|
defaultApiKey: string;
|
||||||
|
logEvent: (payload: Record<string, unknown>) => void;
|
||||||
|
featureAssistantAddressQueryV1: boolean;
|
||||||
|
featureAddressLlmPredecomposeV1: boolean;
|
||||||
|
featureInvestigationStateV1: boolean;
|
||||||
|
featureStateFollowupBindingV1: boolean;
|
||||||
|
featureContractsV11: boolean;
|
||||||
|
featureAnswerPolicyV11: boolean;
|
||||||
|
featureProblemCentricAnswerV1: boolean;
|
||||||
|
featureLifecycleAnswerV1: boolean;
|
||||||
|
defaultModel: string;
|
||||||
|
defaultBaseUrl: string;
|
||||||
|
compactWhitespace: RunAssistantUserTurnBootstrapRuntimeInput["compactWhitespace"];
|
||||||
|
repairAddressMojibake: RunAssistantUserTurnBootstrapRuntimeInput["repairAddressMojibake"];
|
||||||
|
resolveRuntimeAnalysisContext: RunAssistantUserTurnBootstrapRuntimeInput["resolveRuntimeAnalysisContext"];
|
||||||
|
runAddressLlmPreDecompose: (payload: unknown, userMessage: string) => Promise<Record<string, unknown>>;
|
||||||
|
buildAddressLlmPredecomposeContractV1: (...args: any[]) => unknown;
|
||||||
|
sanitizeAddressMessageForFallback: (...args: any[]) => unknown;
|
||||||
|
toNonEmptyString: (...args: any[]) => unknown;
|
||||||
|
resolveAddressFollowupCarryoverContext: (...args: any[]) => unknown;
|
||||||
|
resolveAssistantOrchestrationDecision: (...args: any[]) => unknown;
|
||||||
|
buildAddressDialogContinuationContractV2: (...args: any[]) => unknown;
|
||||||
|
mergeFollowupContextWithOrganizationScope: (...args: any[]) => unknown;
|
||||||
|
isRetryableAddressLimitedResult: (...args: any[]) => unknown;
|
||||||
|
mergeKnownOrganizations: (...args: any[]) => unknown;
|
||||||
|
hasAssistantDataScopeMetaQuestionSignal: (...args: any[]) => unknown;
|
||||||
|
shouldHandleAsAssistantCapabilityMetaQuery: (...args: any[]) => unknown;
|
||||||
|
hasDestructiveDataActionSignal: (...args: any[]) => unknown;
|
||||||
|
hasDangerOrCoercionSignal: (...args: any[]) => unknown;
|
||||||
|
hasOperationalAdminActionRequestSignal: (...args: any[]) => unknown;
|
||||||
|
hasOrganizationFactLookupSignal: (...args: any[]) => unknown;
|
||||||
|
hasOrganizationFactFollowupSignal: (...args: any[]) => unknown;
|
||||||
|
shouldEmitOrganizationSelectionReply: (...args: any[]) => unknown;
|
||||||
|
hasAssistantCapabilityQuestionSignal: (...args: any[]) => unknown;
|
||||||
|
resolveDataScopeProbe: () => unknown;
|
||||||
|
applyScriptGuard: (...args: any[]) => unknown;
|
||||||
|
applyGroundingGuard: (...args: any[]) => unknown;
|
||||||
|
buildAssistantSafetyRefusalReply: (...args: any[]) => unknown;
|
||||||
|
buildAssistantDataScopeContractReply: (...args: any[]) => unknown;
|
||||||
|
buildAssistantOrganizationFactBoundaryReply: (...args: any[]) => unknown;
|
||||||
|
buildAssistantDataScopeSelectionReply: (...args: any[]) => unknown;
|
||||||
|
buildAssistantOperationalBoundaryReply: (...args: any[]) => unknown;
|
||||||
|
buildAssistantCapabilityContractReply: (...args: any[]) => unknown;
|
||||||
|
loadAssistantCanonExcerpt: (...args: any[]) => unknown;
|
||||||
|
sanitizeOutgoingAssistantText: (value: unknown, fallback?: string) => string;
|
||||||
|
buildAddressDebugPayload: (...args: any[]) => unknown;
|
||||||
|
buildAddressFollowupOffer: (...args: any[]) => unknown;
|
||||||
|
buildFollowupStateBinding: (...args: any[]) => unknown;
|
||||||
|
resolveBusinessScopeAlignment: (...args: any[]) => unknown;
|
||||||
|
inferP0DomainFromMessage: (...args: any[]) => unknown;
|
||||||
|
resolveBusinessScopeFromLiveContext: (...args: any[]) => unknown;
|
||||||
|
extractRequirements: (...args: any[]) => unknown;
|
||||||
|
toExecutionPlan: (...args: any[]) => unknown;
|
||||||
|
enforceRbpLiveRoutePlan: (...args: any[]) => unknown;
|
||||||
|
enforceFaLiveRoutePlan: (...args: any[]) => unknown;
|
||||||
|
mapNoRouteReason: (...args: any[]) => unknown;
|
||||||
|
buildSkippedResult: (...args: any[]) => unknown;
|
||||||
|
evaluateCoverage: (...args: any[]) => unknown;
|
||||||
|
checkGrounding: (...args: any[]) => unknown;
|
||||||
|
collectRbpLiveRouteAudit: (...args: any[]) => unknown;
|
||||||
|
collectFaLiveRouteAudit: (...args: any[]) => unknown;
|
||||||
|
hasExplicitPeriodAnchorFromNormalized: (...args: any[]) => unknown;
|
||||||
|
extractDroppedIntentSegments: (...args: any[]) => unknown;
|
||||||
|
toDebugRoutes: (...args: any[]) => unknown;
|
||||||
|
extractExecutionState: (...args: any[]) => unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildAssistantUserTurnBootstrapRuntimeInput(
|
||||||
|
payload: AssistantUserTurnBootstrapPayloadLike,
|
||||||
|
deps: AssistantTurnRuntimeBuilderDeps
|
||||||
|
): RunAssistantUserTurnBootstrapRuntimeInput {
|
||||||
|
return {
|
||||||
|
payload,
|
||||||
|
ensureSession: deps.ensureSession,
|
||||||
|
appendItem: deps.appendItem,
|
||||||
|
getSession: deps.getSession,
|
||||||
|
persistSession: deps.persistSession,
|
||||||
|
compactWhitespace: deps.compactWhitespace,
|
||||||
|
repairAddressMojibake: deps.repairAddressMojibake,
|
||||||
|
resolveRuntimeAnalysisContext: deps.resolveRuntimeAnalysisContext,
|
||||||
|
messageIdFactory: deps.messageIdFactory,
|
||||||
|
nowIso: deps.nowIso
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildAssistantAddressAttemptRuntimeInput<ResponseType = unknown>(
|
||||||
|
runtimeInput: RunAssistantTurnAttemptRuntimeAddressInput,
|
||||||
|
deps: AssistantTurnRuntimeBuilderDeps
|
||||||
|
): RunAssistantAddressAttemptRuntimeInput<ResponseType> {
|
||||||
|
return {
|
||||||
|
featureAssistantAddressQueryV1: deps.featureAssistantAddressQueryV1,
|
||||||
|
sessionId: runtimeInput.sessionId,
|
||||||
|
userMessage: runtimeInput.userMessage,
|
||||||
|
sessionItems: runtimeInput.sessionItems,
|
||||||
|
payload: runtimeInput.payload as any,
|
||||||
|
sessionScope: {
|
||||||
|
knownOrganizations: runtimeInput.sessionOrganizationScope.knownOrganizations,
|
||||||
|
selectedOrganization: runtimeInput.sessionOrganizationScope.selectedOrganization,
|
||||||
|
activeOrganization: runtimeInput.sessionOrganizationScope.activeOrganization
|
||||||
|
},
|
||||||
|
featureAddressLlmPredecomposeV1: deps.featureAddressLlmPredecomposeV1,
|
||||||
|
runAddressLlmPreDecompose: async () => deps.runAddressLlmPreDecompose(runtimeInput.payload, runtimeInput.userMessage),
|
||||||
|
buildAddressLlmPredecomposeContractV1: deps.buildAddressLlmPredecomposeContractV1 as any,
|
||||||
|
sanitizeAddressMessageForFallback: deps.sanitizeAddressMessageForFallback as any,
|
||||||
|
toNonEmptyString: deps.toNonEmptyString as any,
|
||||||
|
resolveAddressFollowupCarryoverContext: deps.resolveAddressFollowupCarryoverContext as any,
|
||||||
|
resolveAssistantOrchestrationDecision: deps.resolveAssistantOrchestrationDecision as any,
|
||||||
|
buildAddressDialogContinuationContractV2: deps.buildAddressDialogContinuationContractV2 as any,
|
||||||
|
runtimeAnalysisContextAsOfDate: runtimeInput.runtimeAnalysisContext.as_of_date,
|
||||||
|
compactWhitespace: deps.compactWhitespace,
|
||||||
|
mergeFollowupContextWithOrganizationScope: deps.mergeFollowupContextWithOrganizationScope as any,
|
||||||
|
runAddressQueryTryHandle: deps.tryAddressQueryHandle as any,
|
||||||
|
isRetryableAddressLimitedResult: deps.isRetryableAddressLimitedResult as any,
|
||||||
|
mergeKnownOrganizations: deps.mergeKnownOrganizations as any,
|
||||||
|
hasAssistantDataScopeMetaQuestionSignal: deps.hasAssistantDataScopeMetaQuestionSignal as any,
|
||||||
|
shouldHandleAsAssistantCapabilityMetaQuery: deps.shouldHandleAsAssistantCapabilityMetaQuery as any,
|
||||||
|
hasDestructiveDataActionSignal: deps.hasDestructiveDataActionSignal as any,
|
||||||
|
hasDangerOrCoercionSignal: deps.hasDangerOrCoercionSignal as any,
|
||||||
|
hasOperationalAdminActionRequestSignal: deps.hasOperationalAdminActionRequestSignal as any,
|
||||||
|
hasOrganizationFactLookupSignal: deps.hasOrganizationFactLookupSignal as any,
|
||||||
|
hasOrganizationFactFollowupSignal: deps.hasOrganizationFactFollowupSignal as any,
|
||||||
|
shouldEmitOrganizationSelectionReply: deps.shouldEmitOrganizationSelectionReply as any,
|
||||||
|
hasAssistantCapabilityQuestionSignal: deps.hasAssistantCapabilityQuestionSignal as any,
|
||||||
|
resolveDataScopeProbe: deps.resolveDataScopeProbe as any,
|
||||||
|
applyScriptGuard: deps.applyScriptGuard as any,
|
||||||
|
applyGroundingGuard: deps.applyGroundingGuard as any,
|
||||||
|
buildAssistantSafetyRefusalReply: deps.buildAssistantSafetyRefusalReply as any,
|
||||||
|
buildAssistantDataScopeContractReply: deps.buildAssistantDataScopeContractReply as any,
|
||||||
|
buildAssistantOrganizationFactBoundaryReply: deps.buildAssistantOrganizationFactBoundaryReply as any,
|
||||||
|
buildAssistantDataScopeSelectionReply: deps.buildAssistantDataScopeSelectionReply as any,
|
||||||
|
buildAssistantOperationalBoundaryReply: deps.buildAssistantOperationalBoundaryReply as any,
|
||||||
|
buildAssistantCapabilityContractReply: deps.buildAssistantCapabilityContractReply as any,
|
||||||
|
chatClient: deps.chatClient as any,
|
||||||
|
loadAssistantCanonExcerpt: deps.loadAssistantCanonExcerpt as any,
|
||||||
|
sanitizeOutgoingAssistantText: deps.sanitizeOutgoingAssistantText,
|
||||||
|
defaultModel: deps.defaultModel,
|
||||||
|
defaultBaseUrl: deps.defaultBaseUrl,
|
||||||
|
defaultApiKey: deps.defaultApiKey,
|
||||||
|
buildAddressDebugPayload: deps.buildAddressDebugPayload as any,
|
||||||
|
buildAddressFollowupOffer: deps.buildAddressFollowupOffer as any,
|
||||||
|
appendItem: deps.appendItem as any,
|
||||||
|
getSession: deps.getSession as any,
|
||||||
|
persistSession: deps.persistSession as any,
|
||||||
|
cloneConversation: (items) => items.map((item) => ({ ...item })),
|
||||||
|
logEvent: deps.logEvent as any,
|
||||||
|
messageIdFactory: deps.messageIdFactory,
|
||||||
|
nowIso: deps.nowIso
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildAssistantDeepTurnAttemptRuntimeInput<ResponseType = unknown>(
|
||||||
|
runtimeInput: RunAssistantTurnAttemptRuntimeDeepInput,
|
||||||
|
deps: AssistantTurnRuntimeBuilderDeps
|
||||||
|
): RunAssistantDeepTurnAttemptRuntimeInput<ResponseType> {
|
||||||
|
return {
|
||||||
|
sessionId: runtimeInput.sessionId,
|
||||||
|
questionId: runtimeInput.questionId,
|
||||||
|
userMessage: runtimeInput.userMessage,
|
||||||
|
payload: runtimeInput.payload as any,
|
||||||
|
runtimeAnalysisContext: runtimeInput.runtimeAnalysisContext as any,
|
||||||
|
sessionInvestigationState: runtimeInput.sessionInvestigationState as any,
|
||||||
|
addressRuntimeMetaForDeep: runtimeInput.addressRuntimeMetaForDeep,
|
||||||
|
featureInvestigationStateV1: deps.featureInvestigationStateV1,
|
||||||
|
featureStateFollowupBindingV1: deps.featureStateFollowupBindingV1,
|
||||||
|
featureContractsV11: deps.featureContractsV11,
|
||||||
|
featureAnswerPolicyV11: deps.featureAnswerPolicyV11,
|
||||||
|
featureProblemCentricAnswerV1: deps.featureProblemCentricAnswerV1,
|
||||||
|
featureLifecycleAnswerV1: deps.featureLifecycleAnswerV1,
|
||||||
|
buildFollowupStateBinding: deps.buildFollowupStateBinding as any,
|
||||||
|
normalize: deps.normalize as any,
|
||||||
|
resolveBusinessScopeAlignment: deps.resolveBusinessScopeAlignment as any,
|
||||||
|
inferP0DomainFromMessage: deps.inferP0DomainFromMessage as any,
|
||||||
|
resolveBusinessScopeFromLiveContext: deps.resolveBusinessScopeFromLiveContext as any,
|
||||||
|
extractRequirements: deps.extractRequirements as any,
|
||||||
|
toExecutionPlan: deps.toExecutionPlan as any,
|
||||||
|
enforceRbpLiveRoutePlan: deps.enforceRbpLiveRoutePlan as any,
|
||||||
|
enforceFaLiveRoutePlan: deps.enforceFaLiveRoutePlan as any,
|
||||||
|
executeRouteRuntime: deps.executeRouteRuntime as any,
|
||||||
|
mapNoRouteReason: deps.mapNoRouteReason as any,
|
||||||
|
buildSkippedResult: deps.buildSkippedResult as any,
|
||||||
|
evaluateCoverage: deps.evaluateCoverage as any,
|
||||||
|
checkGrounding: deps.checkGrounding as any,
|
||||||
|
collectRbpLiveRouteAudit: deps.collectRbpLiveRouteAudit as any,
|
||||||
|
collectFaLiveRouteAudit: deps.collectFaLiveRouteAudit as any,
|
||||||
|
hasExplicitPeriodAnchor: deps.hasExplicitPeriodAnchorFromNormalized as any,
|
||||||
|
extractDroppedIntentSegments: deps.extractDroppedIntentSegments as any,
|
||||||
|
buildDebugRoutes: deps.toDebugRoutes as any,
|
||||||
|
extractExecutionState: deps.extractExecutionState as any,
|
||||||
|
sanitizeReply: deps.sanitizeOutgoingAssistantText as any,
|
||||||
|
persistInvestigationState: deps.setInvestigationState as any,
|
||||||
|
messageIdFactory: deps.messageIdFactory as any,
|
||||||
|
appendItem: deps.appendItem as any,
|
||||||
|
getSession: deps.getSession as any,
|
||||||
|
persistSession: deps.persistSession as any,
|
||||||
|
cloneConversation: (items) => items.map((item) => ({ ...item })),
|
||||||
|
logEvent: deps.logEvent as any
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,165 @@
|
||||||
|
import { describe, expect, it, vi } from "vitest";
|
||||||
|
import {
|
||||||
|
buildAssistantAddressAttemptRuntimeInput,
|
||||||
|
buildAssistantDeepTurnAttemptRuntimeInput,
|
||||||
|
buildAssistantUserTurnBootstrapRuntimeInput
|
||||||
|
} from "../src/services/assistantTurnRuntimeInputBuilder";
|
||||||
|
|
||||||
|
function buildDeps(overrides: Record<string, unknown> = {}) {
|
||||||
|
const noop = vi.fn(() => null);
|
||||||
|
return {
|
||||||
|
ensureSession: vi.fn(() => ({ session_id: "asst-1", items: [], investigation_state: null })),
|
||||||
|
appendItem: vi.fn(),
|
||||||
|
getSession: vi.fn(() => ({ session_id: "asst-1", items: [], investigation_state: null })),
|
||||||
|
persistSession: vi.fn(),
|
||||||
|
setInvestigationState: vi.fn(),
|
||||||
|
normalize: vi.fn(async () => ({})),
|
||||||
|
executeRouteRuntime: vi.fn(async () => ({})),
|
||||||
|
tryAddressQueryHandle: vi.fn(async () => ({ response_type: "READY" })),
|
||||||
|
chatClient: {},
|
||||||
|
messageIdFactory: vi.fn(() => "msg-1"),
|
||||||
|
nowIso: vi.fn(() => "2026-04-11T00:00:00.000Z"),
|
||||||
|
defaultApiKey: "key",
|
||||||
|
logEvent: vi.fn(),
|
||||||
|
featureAssistantAddressQueryV1: true,
|
||||||
|
featureAddressLlmPredecomposeV1: true,
|
||||||
|
featureInvestigationStateV1: true,
|
||||||
|
featureStateFollowupBindingV1: true,
|
||||||
|
featureContractsV11: true,
|
||||||
|
featureAnswerPolicyV11: true,
|
||||||
|
featureProblemCentricAnswerV1: true,
|
||||||
|
featureLifecycleAnswerV1: true,
|
||||||
|
defaultModel: "gpt-5",
|
||||||
|
defaultBaseUrl: "http://localhost",
|
||||||
|
compactWhitespace: vi.fn((value: unknown) => String(value ?? "").trim()),
|
||||||
|
repairAddressMojibake: vi.fn((value: unknown) => String(value ?? "")),
|
||||||
|
resolveRuntimeAnalysisContext: vi.fn(() => ({ as_of_date: "2020-07-31" })),
|
||||||
|
runAddressLlmPreDecompose: vi.fn(async () => ({})),
|
||||||
|
buildAddressLlmPredecomposeContractV1: noop,
|
||||||
|
sanitizeAddressMessageForFallback: noop,
|
||||||
|
toNonEmptyString: vi.fn((value: unknown) =>
|
||||||
|
typeof value === "string" && value.trim().length > 0 ? value.trim() : null
|
||||||
|
),
|
||||||
|
resolveAddressFollowupCarryoverContext: noop,
|
||||||
|
resolveAssistantOrchestrationDecision: noop,
|
||||||
|
buildAddressDialogContinuationContractV2: noop,
|
||||||
|
mergeFollowupContextWithOrganizationScope: noop,
|
||||||
|
isRetryableAddressLimitedResult: noop,
|
||||||
|
mergeKnownOrganizations: noop,
|
||||||
|
hasAssistantDataScopeMetaQuestionSignal: noop,
|
||||||
|
shouldHandleAsAssistantCapabilityMetaQuery: noop,
|
||||||
|
hasDestructiveDataActionSignal: noop,
|
||||||
|
hasDangerOrCoercionSignal: noop,
|
||||||
|
hasOperationalAdminActionRequestSignal: noop,
|
||||||
|
hasOrganizationFactLookupSignal: noop,
|
||||||
|
hasOrganizationFactFollowupSignal: noop,
|
||||||
|
shouldEmitOrganizationSelectionReply: noop,
|
||||||
|
hasAssistantCapabilityQuestionSignal: noop,
|
||||||
|
resolveDataScopeProbe: vi.fn(() => null),
|
||||||
|
applyScriptGuard: noop,
|
||||||
|
applyGroundingGuard: noop,
|
||||||
|
buildAssistantSafetyRefusalReply: noop,
|
||||||
|
buildAssistantDataScopeContractReply: noop,
|
||||||
|
buildAssistantOrganizationFactBoundaryReply: noop,
|
||||||
|
buildAssistantDataScopeSelectionReply: noop,
|
||||||
|
buildAssistantOperationalBoundaryReply: noop,
|
||||||
|
buildAssistantCapabilityContractReply: noop,
|
||||||
|
loadAssistantCanonExcerpt: noop,
|
||||||
|
sanitizeOutgoingAssistantText: vi.fn((value: unknown, fallback = "") => {
|
||||||
|
const text = typeof value === "string" ? value.trim() : "";
|
||||||
|
return text || fallback;
|
||||||
|
}),
|
||||||
|
buildAddressDebugPayload: noop,
|
||||||
|
buildAddressFollowupOffer: noop,
|
||||||
|
buildFollowupStateBinding: noop,
|
||||||
|
resolveBusinessScopeAlignment: noop,
|
||||||
|
inferP0DomainFromMessage: noop,
|
||||||
|
resolveBusinessScopeFromLiveContext: noop,
|
||||||
|
extractRequirements: noop,
|
||||||
|
toExecutionPlan: noop,
|
||||||
|
enforceRbpLiveRoutePlan: noop,
|
||||||
|
enforceFaLiveRoutePlan: noop,
|
||||||
|
mapNoRouteReason: noop,
|
||||||
|
buildSkippedResult: noop,
|
||||||
|
evaluateCoverage: noop,
|
||||||
|
checkGrounding: noop,
|
||||||
|
collectRbpLiveRouteAudit: noop,
|
||||||
|
collectFaLiveRouteAudit: noop,
|
||||||
|
hasExplicitPeriodAnchorFromNormalized: noop,
|
||||||
|
extractDroppedIntentSegments: noop,
|
||||||
|
toDebugRoutes: noop,
|
||||||
|
extractExecutionState: noop,
|
||||||
|
...overrides
|
||||||
|
} as any;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("assistant turn runtime input builder", () => {
|
||||||
|
it("builds bootstrap runtime input from shared deps", () => {
|
||||||
|
const deps = buildDeps();
|
||||||
|
const payload = {
|
||||||
|
session_id: "asst-1",
|
||||||
|
user_message: "hello"
|
||||||
|
};
|
||||||
|
|
||||||
|
const runtimeInput = buildAssistantUserTurnBootstrapRuntimeInput(payload, deps);
|
||||||
|
|
||||||
|
expect(runtimeInput.payload).toBe(payload);
|
||||||
|
expect(runtimeInput.ensureSession).toBe(deps.ensureSession);
|
||||||
|
expect(runtimeInput.messageIdFactory?.()).toBe("msg-1");
|
||||||
|
expect(runtimeInput.nowIso?.()).toBe("2026-04-11T00:00:00.000Z");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("builds address attempt input and preserves address context mapping", async () => {
|
||||||
|
const runAddressLlmPreDecompose = vi.fn(async () => ({ mode: "supported" }));
|
||||||
|
const deps = buildDeps({ runAddressLlmPreDecompose });
|
||||||
|
const runtimeInput = {
|
||||||
|
payload: { context: { period_hint: "2020-07-31" } },
|
||||||
|
sessionId: "asst-1",
|
||||||
|
userMessage: "где хвост",
|
||||||
|
sessionItems: [],
|
||||||
|
runtimeAnalysisContext: { as_of_date: "2020-07-31" },
|
||||||
|
sessionOrganizationScope: {
|
||||||
|
knownOrganizations: ["Org A"],
|
||||||
|
selectedOrganization: "Org A",
|
||||||
|
activeOrganization: "Org A"
|
||||||
|
}
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
const built = buildAssistantAddressAttemptRuntimeInput(runtimeInput, deps);
|
||||||
|
const predecompose = await built.runAddressLlmPreDecompose();
|
||||||
|
await built.runAddressQueryTryHandle("message", { analysisDateHint: "2020-07-31" });
|
||||||
|
|
||||||
|
expect(predecompose).toEqual({ mode: "supported" });
|
||||||
|
expect(runAddressLlmPreDecompose).toHaveBeenCalledWith(runtimeInput.payload, "где хвост");
|
||||||
|
expect(built.runtimeAnalysisContextAsOfDate).toBe("2020-07-31");
|
||||||
|
expect(built.sessionScope).toEqual(runtimeInput.sessionOrganizationScope);
|
||||||
|
expect(deps.tryAddressQueryHandle).toHaveBeenCalledWith("message", { analysisDateHint: "2020-07-31" });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("builds deep attempt input with shared guards and state hooks", () => {
|
||||||
|
const setInvestigationState = vi.fn();
|
||||||
|
const sanitizeOutgoingAssistantText = vi.fn(() => "safe");
|
||||||
|
const deps = buildDeps({ setInvestigationState, sanitizeOutgoingAssistantText });
|
||||||
|
const runtimeInput = {
|
||||||
|
payload: { useMock: true },
|
||||||
|
sessionId: "asst-1",
|
||||||
|
questionId: "msg-q1",
|
||||||
|
userMessage: "почему долг не закрыт",
|
||||||
|
runtimeAnalysisContext: { as_of_date: "2020-07-31" },
|
||||||
|
sessionInvestigationState: { scope: "settlements_60_62" },
|
||||||
|
addressRuntimeMetaForDeep: { attempted: true }
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
const built = buildAssistantDeepTurnAttemptRuntimeInput(runtimeInput, deps);
|
||||||
|
const sanitized = built.sanitizeReply(" raw ", "fallback");
|
||||||
|
built.persistInvestigationState("asst-1", { scope: "next" });
|
||||||
|
|
||||||
|
expect(sanitized).toBe("safe");
|
||||||
|
expect(sanitizeOutgoingAssistantText).toHaveBeenCalledWith(" raw ", "fallback");
|
||||||
|
expect(setInvestigationState).toHaveBeenCalledWith("asst-1", { scope: "next" });
|
||||||
|
expect(built.sessionId).toBe("asst-1");
|
||||||
|
expect(built.questionId).toBe("msg-q1");
|
||||||
|
expect(built.addressRuntimeMetaForDeep).toEqual({ attempted: true });
|
||||||
|
expect(built.featureContractsV11).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue