ГЛОБАЛЬНЫЙ РЕФАКТОРИНГ АРХИТЕКТУРЫ - Рефакторинг этапов 2.42: вынос finalizeAddressLaneResponse из assistantService в отдельный attempt-bridge (как для living chat), для уменьшения монолита без изменения поведения.
This commit is contained in:
parent
fbf2d6a19a
commit
875f3bfbcd
|
|
@ -1316,7 +1316,35 @@ Validation:
|
|||
- `assistantDeepTurnPackagingRuntimeAdapter.test.ts`
|
||||
- `assistantWave10SettlementCorrectiveRegression.test.ts`
|
||||
|
||||
Status: **In progress (Phase 2.1 + 2.2 + 2.3 + 2.4 + 2.5 + 2.6 + 2.7 + 2.8 + 2.9 + 2.10 + 2.11 + 2.12 + 2.13 + 2.14 + 2.15 + 2.16 + 2.17 + 2.18 + 2.19 + 2.20 + 2.21 + 2.22 + 2.23 + 2.24 + 2.25 + 2.26 + 2.27 + 2.28 + 2.29 + 2.30 + 2.31 + 2.32 + 2.33 + 2.34 + 2.35 + 2.36 + 2.37 + 2.38 + 2.39 + 2.40 + 2.41 completed)**
|
||||
Implemented in current pass (Phase 2.42):
|
||||
1. Extracted address-lane response attempt bridge (`finalizeAddressLaneResponse`) from `assistantService` into dedicated runtime adapter:
|
||||
- `assistantAddressLaneResponseAttemptRuntimeAdapter.ts`
|
||||
- introduced:
|
||||
- `runAssistantAddressLaneResponseAttemptRuntime(...)`
|
||||
2. Centralized address-lane response handoff logic (behavior-preserving):
|
||||
- delegated response runtime invocation (`runAssistantAddressLaneResponseRuntime(...)`);
|
||||
- preserved followup-offer/debug payload and session finalization contract wiring.
|
||||
3. Rewired `assistantService` to consume address-lane response attempt runtime adapter.
|
||||
4. Added focused unit tests:
|
||||
- `assistantAddressLaneResponseAttemptRuntimeAdapter.test.ts`
|
||||
|
||||
Validation:
|
||||
1. `npm run build` passed.
|
||||
2. Targeted living/address/deep followup pack passed:
|
||||
- `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 completed)**
|
||||
|
||||
## Stage 3 (P2): Hybrid Semantic Layer (LLM + Deterministic Guards)
|
||||
|
||||
|
|
|
|||
29
llm_normalizer/backend/dist/services/assistantAddressLaneResponseAttemptRuntimeAdapter.js
vendored
Normal file
29
llm_normalizer/backend/dist/services/assistantAddressLaneResponseAttemptRuntimeAdapter.js
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.runAssistantAddressLaneResponseAttemptRuntime = runAssistantAddressLaneResponseAttemptRuntime;
|
||||
const assistantAddressLaneResponseRuntimeAdapter_1 = require("./assistantAddressLaneResponseRuntimeAdapter");
|
||||
function runAssistantAddressLaneResponseAttemptRuntime(input) {
|
||||
const runAddressLaneResponseRuntimeSafe = input.runAddressLaneResponseRuntime ?? assistantAddressLaneResponseRuntimeAdapter_1.runAssistantAddressLaneResponseRuntime;
|
||||
const runtime = runAddressLaneResponseRuntimeSafe({
|
||||
sessionId: input.sessionId,
|
||||
userMessage: input.userMessage,
|
||||
effectiveAddressUserMessage: input.effectiveAddressUserMessage,
|
||||
addressLane: input.addressLane,
|
||||
carryoverMeta: input.carryoverMeta,
|
||||
llmPreDecomposeMeta: input.llmPreDecomposeMeta,
|
||||
knownOrganizations: input.knownOrganizations,
|
||||
activeOrganization: input.activeOrganization,
|
||||
sanitizeOutgoingAssistantText: input.sanitizeOutgoingAssistantText,
|
||||
buildAddressDebugPayload: input.buildAddressDebugPayload,
|
||||
buildAddressFollowupOffer: input.buildAddressFollowupOffer,
|
||||
mergeKnownOrganizations: input.mergeKnownOrganizations,
|
||||
toNonEmptyString: input.toNonEmptyString,
|
||||
appendItem: input.appendItem,
|
||||
getSession: input.getSession,
|
||||
persistSession: input.persistSession,
|
||||
cloneConversation: input.cloneConversation,
|
||||
logEvent: input.logEvent,
|
||||
messageIdFactory: input.messageIdFactory
|
||||
});
|
||||
return runtime.response;
|
||||
}
|
||||
|
|
@ -65,7 +65,7 @@ const openaiResponsesClient_1 = __importStar(require("./openaiResponsesClient"))
|
|||
const addressMcpClient_1 = __importStar(require("./addressMcpClient"));
|
||||
const capabilitiesRegistry_1 = __importStar(require("./capabilitiesRegistry"));
|
||||
const assistantCanon_1 = __importStar(require("./assistantCanon"));
|
||||
const assistantAddressLaneResponseRuntimeAdapter_1 = __importStar(require("./assistantAddressLaneResponseRuntimeAdapter"));
|
||||
const assistantAddressLaneResponseAttemptRuntimeAdapter_1 = __importStar(require("./assistantAddressLaneResponseAttemptRuntimeAdapter"));
|
||||
const assistantCoverageGrounding_1 = __importStar(require("./assistantCoverageGrounding"));
|
||||
const assistantDeepTurnAnalysisRuntimeAdapter_1 = __importStar(require("./assistantDeepTurnAnalysisRuntimeAdapter"));
|
||||
const assistantDeepTurnCompositionRuntimeAdapter_1 = __importStar(require("./assistantDeepTurnCompositionRuntimeAdapter"));
|
||||
|
|
@ -4398,30 +4398,27 @@ class AssistantService {
|
|||
nowIso: () => new Date().toISOString()
|
||||
});
|
||||
const sessionOrganizationScope = resolveSessionOrganizationScopeContext(userMessage, session.items);
|
||||
const finalizeAddressLaneResponse = (addressLane, effectiveAddressUserMessage, carryoverMeta = null, llmPreDecomposeMeta = null) => {
|
||||
const runtime = (0, assistantAddressLaneResponseRuntimeAdapter_1.runAssistantAddressLaneResponseRuntime)({
|
||||
sessionId,
|
||||
userMessage,
|
||||
effectiveAddressUserMessage,
|
||||
addressLane,
|
||||
carryoverMeta,
|
||||
llmPreDecomposeMeta,
|
||||
knownOrganizations: sessionOrganizationScope.knownOrganizations,
|
||||
activeOrganization: sessionOrganizationScope.activeOrganization,
|
||||
sanitizeOutgoingAssistantText,
|
||||
buildAddressDebugPayload,
|
||||
buildAddressFollowupOffer,
|
||||
mergeKnownOrganizations,
|
||||
toNonEmptyString,
|
||||
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: (payload) => (0, log_1.logJson)(payload),
|
||||
messageIdFactory: () => `msg-${(0, nanoid_1.nanoid)(10)}`
|
||||
});
|
||||
return runtime.response;
|
||||
};
|
||||
const finalizeAddressLaneResponse = (addressLane, effectiveAddressUserMessage, carryoverMeta = null, llmPreDecomposeMeta = null) => (0, assistantAddressLaneResponseAttemptRuntimeAdapter_1.runAssistantAddressLaneResponseAttemptRuntime)({
|
||||
sessionId,
|
||||
userMessage,
|
||||
effectiveAddressUserMessage,
|
||||
addressLane,
|
||||
carryoverMeta,
|
||||
llmPreDecomposeMeta,
|
||||
knownOrganizations: sessionOrganizationScope.knownOrganizations,
|
||||
activeOrganization: sessionOrganizationScope.activeOrganization,
|
||||
sanitizeOutgoingAssistantText,
|
||||
buildAddressDebugPayload,
|
||||
buildAddressFollowupOffer,
|
||||
mergeKnownOrganizations,
|
||||
toNonEmptyString,
|
||||
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: (payload) => (0, log_1.logJson)(payload),
|
||||
messageIdFactory: () => `msg-${(0, nanoid_1.nanoid)(10)}`
|
||||
});
|
||||
const tryHandleLivingChat = async (modeDecision, addressRuntimeMeta = null) => (0, assistantLivingChatAttemptRuntimeAdapter_1.runAssistantLivingChatAttemptRuntime)({
|
||||
sessionId,
|
||||
userMessage,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
import type { AssistantMessageResponsePayload } from "../types/assistant";
|
||||
import {
|
||||
runAssistantAddressLaneResponseRuntime,
|
||||
type RunAssistantAddressLaneResponseRuntimeInput,
|
||||
type RunAssistantAddressLaneResponseRuntimeOutput
|
||||
} from "./assistantAddressLaneResponseRuntimeAdapter";
|
||||
|
||||
export interface RunAssistantAddressLaneResponseAttemptRuntimeInput<
|
||||
ResponseType = AssistantMessageResponsePayload
|
||||
> extends RunAssistantAddressLaneResponseRuntimeInput<ResponseType> {
|
||||
runAddressLaneResponseRuntime?: (
|
||||
input: RunAssistantAddressLaneResponseRuntimeInput<ResponseType>
|
||||
) => RunAssistantAddressLaneResponseRuntimeOutput<ResponseType>;
|
||||
}
|
||||
|
||||
export function runAssistantAddressLaneResponseAttemptRuntime<
|
||||
ResponseType = AssistantMessageResponsePayload
|
||||
>(
|
||||
input: RunAssistantAddressLaneResponseAttemptRuntimeInput<ResponseType>
|
||||
): ResponseType {
|
||||
const runAddressLaneResponseRuntimeSafe =
|
||||
input.runAddressLaneResponseRuntime ?? runAssistantAddressLaneResponseRuntime;
|
||||
const runtime = runAddressLaneResponseRuntimeSafe({
|
||||
sessionId: input.sessionId,
|
||||
userMessage: input.userMessage,
|
||||
effectiveAddressUserMessage: input.effectiveAddressUserMessage,
|
||||
addressLane: input.addressLane,
|
||||
carryoverMeta: input.carryoverMeta,
|
||||
llmPreDecomposeMeta: input.llmPreDecomposeMeta,
|
||||
knownOrganizations: input.knownOrganizations,
|
||||
activeOrganization: input.activeOrganization,
|
||||
sanitizeOutgoingAssistantText: input.sanitizeOutgoingAssistantText,
|
||||
buildAddressDebugPayload: input.buildAddressDebugPayload,
|
||||
buildAddressFollowupOffer: input.buildAddressFollowupOffer,
|
||||
mergeKnownOrganizations: input.mergeKnownOrganizations,
|
||||
toNonEmptyString: input.toNonEmptyString,
|
||||
appendItem: input.appendItem,
|
||||
getSession: input.getSession,
|
||||
persistSession: input.persistSession,
|
||||
cloneConversation: input.cloneConversation,
|
||||
logEvent: input.logEvent,
|
||||
messageIdFactory: input.messageIdFactory
|
||||
});
|
||||
return runtime.response;
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@ import * as openaiResponsesClient_1 from "./openaiResponsesClient";
|
|||
import * as addressMcpClient_1 from "./addressMcpClient";
|
||||
import * as capabilitiesRegistry_1 from "./capabilitiesRegistry";
|
||||
import * as assistantCanon_1 from "./assistantCanon";
|
||||
import * as assistantAddressLaneResponseRuntimeAdapter_1 from "./assistantAddressLaneResponseRuntimeAdapter";
|
||||
import * as assistantAddressLaneResponseAttemptRuntimeAdapter_1 from "./assistantAddressLaneResponseAttemptRuntimeAdapter";
|
||||
import * as assistantCoverageGrounding_1 from "./assistantCoverageGrounding";
|
||||
import * as assistantDeepTurnAnalysisRuntimeAdapter_1 from "./assistantDeepTurnAnalysisRuntimeAdapter";
|
||||
import * as assistantDeepTurnCompositionRuntimeAdapter_1 from "./assistantDeepTurnCompositionRuntimeAdapter";
|
||||
|
|
@ -4353,8 +4353,7 @@ export class AssistantService {
|
|||
nowIso: () => new Date().toISOString()
|
||||
});
|
||||
const sessionOrganizationScope = resolveSessionOrganizationScopeContext(userMessage, session.items);
|
||||
const finalizeAddressLaneResponse = (addressLane, effectiveAddressUserMessage, carryoverMeta = null, llmPreDecomposeMeta = null) => {
|
||||
const runtime = (0, assistantAddressLaneResponseRuntimeAdapter_1.runAssistantAddressLaneResponseRuntime)({
|
||||
const finalizeAddressLaneResponse = (addressLane, effectiveAddressUserMessage, carryoverMeta = null, llmPreDecomposeMeta = null) => (0, assistantAddressLaneResponseAttemptRuntimeAdapter_1.runAssistantAddressLaneResponseAttemptRuntime)({
|
||||
sessionId,
|
||||
userMessage,
|
||||
effectiveAddressUserMessage,
|
||||
|
|
@ -4375,8 +4374,6 @@ export class AssistantService {
|
|||
logEvent: (payload) => (0, log_1.logJson)(payload),
|
||||
messageIdFactory: () => `msg-${(0, nanoid_1.nanoid)(10)}`
|
||||
});
|
||||
return runtime.response;
|
||||
};
|
||||
const tryHandleLivingChat = async (modeDecision, addressRuntimeMeta = null) => (0, assistantLivingChatAttemptRuntimeAdapter_1.runAssistantLivingChatAttemptRuntime)({
|
||||
sessionId,
|
||||
userMessage,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,84 @@
|
|||
import { describe, expect, it, vi } from "vitest";
|
||||
import { runAssistantAddressLaneResponseAttemptRuntime } from "../src/services/assistantAddressLaneResponseAttemptRuntimeAdapter";
|
||||
|
||||
function buildInput(overrides: Record<string, unknown> = {}) {
|
||||
return {
|
||||
sessionId: "asst-1",
|
||||
userMessage: "где хвост по оплате",
|
||||
effectiveAddressUserMessage: "где хвост по оплате",
|
||||
addressLane: {
|
||||
reply_text: "address reply",
|
||||
reply_type: "factual_with_explanation",
|
||||
debug: { extracted_filters: {} }
|
||||
},
|
||||
carryoverMeta: null,
|
||||
llmPreDecomposeMeta: null,
|
||||
knownOrganizations: [],
|
||||
activeOrganization: null,
|
||||
sanitizeOutgoingAssistantText: (value: unknown, fallback = "") => {
|
||||
const text = String(value ?? "").trim();
|
||||
return text || fallback;
|
||||
},
|
||||
buildAddressDebugPayload: () => ({}),
|
||||
buildAddressFollowupOffer: () => null,
|
||||
mergeKnownOrganizations: (value: string[]) => value,
|
||||
toNonEmptyString: (value: unknown) => (typeof value === "string" && value.trim() ? value.trim() : null),
|
||||
appendItem: () => {},
|
||||
getSession: () => ({
|
||||
session_id: "asst-1",
|
||||
updated_at: "",
|
||||
items: [],
|
||||
investigation_state: null
|
||||
}),
|
||||
persistSession: () => {},
|
||||
cloneConversation: (items: unknown[]) => items,
|
||||
logEvent: () => {},
|
||||
messageIdFactory: () => "msg-1",
|
||||
...overrides
|
||||
} as any;
|
||||
}
|
||||
|
||||
describe("assistant address lane response attempt runtime adapter", () => {
|
||||
it("returns delegated runtime response", () => {
|
||||
const runAddressLaneResponseRuntime = vi.fn(() => ({
|
||||
response: { ok: true, lane: "address" },
|
||||
debug: { marker: "v1" }
|
||||
}));
|
||||
|
||||
const response = runAssistantAddressLaneResponseAttemptRuntime(
|
||||
buildInput({ runAddressLaneResponseRuntime })
|
||||
);
|
||||
|
||||
expect(response).toEqual({ ok: true, lane: "address" });
|
||||
expect(runAddressLaneResponseRuntime).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
sessionId: "asst-1",
|
||||
userMessage: "где хвост по оплате"
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it("forwards carryover and llm predecompose metadata", () => {
|
||||
const carryoverMeta = { previousReplyType: "partial_coverage" };
|
||||
const llmPreDecomposeMeta = { mode: "supported", confidence: "high" };
|
||||
const runAddressLaneResponseRuntime = vi.fn(() => ({
|
||||
response: { ok: true },
|
||||
debug: {}
|
||||
}));
|
||||
|
||||
runAssistantAddressLaneResponseAttemptRuntime(
|
||||
buildInput({
|
||||
carryoverMeta,
|
||||
llmPreDecomposeMeta,
|
||||
runAddressLaneResponseRuntime
|
||||
})
|
||||
);
|
||||
|
||||
expect(runAddressLaneResponseRuntime).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
carryoverMeta,
|
||||
llmPreDecomposeMeta
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue