ГЛОБАЛЬНЫЙ РЕФАКТОРИНГ АРХИТЕКТУРЫ - Рефакторинг этапов 2.49: вынос turnRuntimeDeps (фабрику зависимостей) из assistantService в отдельный deps-adapter, чтобы handleMessage стал совсем тонким.
This commit is contained in:
parent
f1e621fccc
commit
ca467cdecc
|
|
@ -1537,7 +1537,42 @@ 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 + 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)
|
## 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 assistantTurnRuntimeDepsAdapter_1 = __importStar(require("./assistantTurnRuntimeDepsAdapter"));
|
||||||
const assistantTurnRuntimeInputBuilder_1 = __importStar(require("./assistantTurnRuntimeInputBuilder"));
|
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"));
|
||||||
|
|
@ -4371,20 +4372,18 @@ class AssistantService {
|
||||||
return this.sessions.getSession(sessionId);
|
return this.sessions.getSession(sessionId);
|
||||||
}
|
}
|
||||||
async handleMessage(payload) {
|
async handleMessage(payload) {
|
||||||
const turnRuntimeDeps = {
|
const turnRuntimeDeps = (0, assistantTurnRuntimeDepsAdapter_1.buildAssistantTurnRuntimeDeps)({
|
||||||
ensureSession: (targetSessionId) => this.sessions.ensureSession(targetSessionId),
|
sessions: this.sessions,
|
||||||
appendItem: (targetSessionId, item) => this.sessions.appendItem(targetSessionId, item),
|
sessionLogger: this.sessionLogger,
|
||||||
getSession: (targetSessionId) => this.sessions.getSession(targetSessionId),
|
normalizerService: this.normalizerService,
|
||||||
persistSession: (sessionState) => this.sessionLogger.persistSession(sessionState),
|
dataLayer: this.dataLayer,
|
||||||
setInvestigationState: (targetSessionId, snapshot) => this.sessions.setInvestigationState(targetSessionId, snapshot),
|
addressQueryService: this.addressQueryService,
|
||||||
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,
|
chatClient: this.chatClient,
|
||||||
messageIdFactory: () => `msg-${(0, nanoid_1.nanoid)(10)}`,
|
messageIdFactory: () => `msg-${(0, nanoid_1.nanoid)(10)}`,
|
||||||
nowIso: () => new Date().toISOString(),
|
nowIso: () => new Date().toISOString(),
|
||||||
defaultApiKey: process.env.OPENAI_API_KEY ?? "",
|
defaultApiKey: process.env.OPENAI_API_KEY ?? "",
|
||||||
logEvent: (runtimePayload) => (0, log_1.logJson)(runtimePayload),
|
logEvent: (runtimePayload) => (0, log_1.logJson)(runtimePayload),
|
||||||
|
flags: {
|
||||||
featureAssistantAddressQueryV1: config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_V1,
|
featureAssistantAddressQueryV1: config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_V1,
|
||||||
featureAddressLlmPredecomposeV1: config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_LLM_PREDECOMPOSE_V1,
|
featureAddressLlmPredecomposeV1: config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_LLM_PREDECOMPOSE_V1,
|
||||||
featureInvestigationStateV1: config_1.FEATURE_ASSISTANT_INVESTIGATION_STATE_V1,
|
featureInvestigationStateV1: config_1.FEATURE_ASSISTANT_INVESTIGATION_STATE_V1,
|
||||||
|
|
@ -4392,9 +4391,13 @@ class AssistantService {
|
||||||
featureContractsV11: config_1.FEATURE_ASSISTANT_CONTRACTS_V11,
|
featureContractsV11: config_1.FEATURE_ASSISTANT_CONTRACTS_V11,
|
||||||
featureAnswerPolicyV11: config_1.FEATURE_ASSISTANT_ANSWER_POLICY_V11,
|
featureAnswerPolicyV11: config_1.FEATURE_ASSISTANT_ANSWER_POLICY_V11,
|
||||||
featureProblemCentricAnswerV1: config_1.FEATURE_ASSISTANT_PROBLEM_CENTRIC_ANSWER_V1,
|
featureProblemCentricAnswerV1: config_1.FEATURE_ASSISTANT_PROBLEM_CENTRIC_ANSWER_V1,
|
||||||
featureLifecycleAnswerV1: config_1.FEATURE_ASSISTANT_LIFECYCLE_ANSWER_V1,
|
featureLifecycleAnswerV1: config_1.FEATURE_ASSISTANT_LIFECYCLE_ANSWER_V1
|
||||||
|
},
|
||||||
|
defaults: {
|
||||||
defaultModel: config_1.DEFAULT_MODEL,
|
defaultModel: config_1.DEFAULT_MODEL,
|
||||||
defaultBaseUrl: config_1.DEFAULT_OPENAI_BASE_URL,
|
defaultBaseUrl: config_1.DEFAULT_OPENAI_BASE_URL
|
||||||
|
},
|
||||||
|
helpers: {
|
||||||
compactWhitespace,
|
compactWhitespace,
|
||||||
repairAddressMojibake,
|
repairAddressMojibake,
|
||||||
resolveRuntimeAnalysisContext,
|
resolveRuntimeAnalysisContext,
|
||||||
|
|
@ -4448,7 +4451,8 @@ class AssistantService {
|
||||||
extractDroppedIntentSegments: (normalizedPayload) => extractDiscardedIntentSegments(normalizedPayload),
|
extractDroppedIntentSegments: (normalizedPayload) => extractDiscardedIntentSegments(normalizedPayload),
|
||||||
toDebugRoutes: (routeSummary) => toDebugRoutes(routeSummary),
|
toDebugRoutes: (routeSummary) => toDebugRoutes(routeSummary),
|
||||||
extractExecutionState
|
extractExecutionState
|
||||||
};
|
}
|
||||||
|
});
|
||||||
const turnRuntime = await (0, assistantTurnAttemptRuntimeAdapter_1.runAssistantTurnAttemptRuntime)({
|
const turnRuntime = await (0, assistantTurnAttemptRuntimeAdapter_1.runAssistantTurnAttemptRuntime)({
|
||||||
payload,
|
payload,
|
||||||
runUserTurnBootstrapRuntime: (runtimePayload) => (0, assistantUserTurnBootstrapRuntimeAdapter_1.runAssistantUserTurnBootstrapRuntime)((0, assistantTurnRuntimeInputBuilder_1.buildAssistantUserTurnBootstrapRuntimeInput)(runtimePayload, turnRuntimeDeps)),
|
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 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 assistantTurnRuntimeDepsAdapter_1 from "./assistantTurnRuntimeDepsAdapter";
|
||||||
import * as assistantTurnRuntimeInputBuilder_1 from "./assistantTurnRuntimeInputBuilder";
|
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";
|
||||||
|
|
@ -4326,20 +4327,18 @@ export class AssistantService {
|
||||||
return this.sessions.getSession(sessionId);
|
return this.sessions.getSession(sessionId);
|
||||||
}
|
}
|
||||||
async handleMessage(payload) {
|
async handleMessage(payload) {
|
||||||
const turnRuntimeDeps = {
|
const turnRuntimeDeps = (0, assistantTurnRuntimeDepsAdapter_1.buildAssistantTurnRuntimeDeps)({
|
||||||
ensureSession: (targetSessionId) => this.sessions.ensureSession(targetSessionId),
|
sessions: this.sessions,
|
||||||
appendItem: (targetSessionId, item) => this.sessions.appendItem(targetSessionId, item),
|
sessionLogger: this.sessionLogger,
|
||||||
getSession: (targetSessionId) => this.sessions.getSession(targetSessionId),
|
normalizerService: this.normalizerService,
|
||||||
persistSession: (sessionState) => this.sessionLogger.persistSession(sessionState),
|
dataLayer: this.dataLayer,
|
||||||
setInvestigationState: (targetSessionId, snapshot) => this.sessions.setInvestigationState(targetSessionId, snapshot),
|
addressQueryService: this.addressQueryService,
|
||||||
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,
|
chatClient: this.chatClient,
|
||||||
messageIdFactory: () => `msg-${(0, nanoid_1.nanoid)(10)}`,
|
messageIdFactory: () => `msg-${(0, nanoid_1.nanoid)(10)}`,
|
||||||
nowIso: () => new Date().toISOString(),
|
nowIso: () => new Date().toISOString(),
|
||||||
defaultApiKey: process.env.OPENAI_API_KEY ?? "",
|
defaultApiKey: process.env.OPENAI_API_KEY ?? "",
|
||||||
logEvent: (runtimePayload) => (0, log_1.logJson)(runtimePayload),
|
logEvent: (runtimePayload) => (0, log_1.logJson)(runtimePayload),
|
||||||
|
flags: {
|
||||||
featureAssistantAddressQueryV1: config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_V1,
|
featureAssistantAddressQueryV1: config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_V1,
|
||||||
featureAddressLlmPredecomposeV1: config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_LLM_PREDECOMPOSE_V1,
|
featureAddressLlmPredecomposeV1: config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_LLM_PREDECOMPOSE_V1,
|
||||||
featureInvestigationStateV1: config_1.FEATURE_ASSISTANT_INVESTIGATION_STATE_V1,
|
featureInvestigationStateV1: config_1.FEATURE_ASSISTANT_INVESTIGATION_STATE_V1,
|
||||||
|
|
@ -4347,9 +4346,13 @@ export class AssistantService {
|
||||||
featureContractsV11: config_1.FEATURE_ASSISTANT_CONTRACTS_V11,
|
featureContractsV11: config_1.FEATURE_ASSISTANT_CONTRACTS_V11,
|
||||||
featureAnswerPolicyV11: config_1.FEATURE_ASSISTANT_ANSWER_POLICY_V11,
|
featureAnswerPolicyV11: config_1.FEATURE_ASSISTANT_ANSWER_POLICY_V11,
|
||||||
featureProblemCentricAnswerV1: config_1.FEATURE_ASSISTANT_PROBLEM_CENTRIC_ANSWER_V1,
|
featureProblemCentricAnswerV1: config_1.FEATURE_ASSISTANT_PROBLEM_CENTRIC_ANSWER_V1,
|
||||||
featureLifecycleAnswerV1: config_1.FEATURE_ASSISTANT_LIFECYCLE_ANSWER_V1,
|
featureLifecycleAnswerV1: config_1.FEATURE_ASSISTANT_LIFECYCLE_ANSWER_V1
|
||||||
|
},
|
||||||
|
defaults: {
|
||||||
defaultModel: config_1.DEFAULT_MODEL,
|
defaultModel: config_1.DEFAULT_MODEL,
|
||||||
defaultBaseUrl: config_1.DEFAULT_OPENAI_BASE_URL,
|
defaultBaseUrl: config_1.DEFAULT_OPENAI_BASE_URL
|
||||||
|
},
|
||||||
|
helpers: {
|
||||||
compactWhitespace,
|
compactWhitespace,
|
||||||
repairAddressMojibake,
|
repairAddressMojibake,
|
||||||
resolveRuntimeAnalysisContext,
|
resolveRuntimeAnalysisContext,
|
||||||
|
|
@ -4403,7 +4406,8 @@ export class AssistantService {
|
||||||
extractDroppedIntentSegments: (normalizedPayload) => extractDiscardedIntentSegments(normalizedPayload),
|
extractDroppedIntentSegments: (normalizedPayload) => extractDiscardedIntentSegments(normalizedPayload),
|
||||||
toDebugRoutes: (routeSummary) => toDebugRoutes(routeSummary),
|
toDebugRoutes: (routeSummary) => toDebugRoutes(routeSummary),
|
||||||
extractExecutionState
|
extractExecutionState
|
||||||
};
|
}
|
||||||
|
});
|
||||||
const turnRuntime = await (0, assistantTurnAttemptRuntimeAdapter_1.runAssistantTurnAttemptRuntime)({
|
const turnRuntime = await (0, assistantTurnAttemptRuntimeAdapter_1.runAssistantTurnAttemptRuntime)({
|
||||||
payload,
|
payload,
|
||||||
runUserTurnBootstrapRuntime: (runtimePayload) => (0, assistantUserTurnBootstrapRuntimeAdapter_1.runAssistantUserTurnBootstrapRuntime)((0, assistantTurnRuntimeInputBuilder_1.buildAssistantUserTurnBootstrapRuntimeInput)(runtimePayload, turnRuntimeDeps)),
|
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