ГЛОБАЛЬНЫЙ РЕФАКТОРИНГ АРХИТЕКТУРЫ - Рефакторинг этапов 2.612.64 - вынос mapper для assistantAddressLaneResponseAttemptRuntimeAdapter и для assistantLivingChatAttemptRuntimeAdapter / сборка входов для living chat attempt в отдельный builder (LLM + handler)
This commit is contained in:
parent
6c9b94ef34
commit
79b636bfe6
|
|
@ -1751,7 +1751,55 @@ Validation:
|
|||
- `assistantWave10SettlementCorrectiveRegression.test.ts`
|
||||
- `assistantLivingChatMode.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 + 2.50 + 2.51 + 2.52 + 2.53 + 2.54 + 2.55 + 2.56 + 2.57 + 2.58 + 2.59 + 2.60 completed)**
|
||||
Implemented in current pass (Phase 2.61 + 2.62 + 2.63 + 2.64):
|
||||
1. Added dedicated runtime input builder for address lane response runtime:
|
||||
- `assistantAddressLaneResponseRuntimeInputBuilder.ts`
|
||||
- introduced:
|
||||
- `buildAssistantAddressLaneResponseRuntimeInput(...)`
|
||||
2. Rewired `assistantAddressLaneResponseAttemptRuntimeAdapter` to consume the new builder (behavior-preserving):
|
||||
- removed inline mapping from attempt input to response runtime input.
|
||||
3. Added dedicated runtime input builders for living-chat attempt orchestration:
|
||||
- `assistantLivingChatAttemptRuntimeInputBuilder.ts`
|
||||
- introduced:
|
||||
- `buildAssistantLivingChatLlmRuntimeInput(...)`
|
||||
- `buildAssistantLivingChatHandlerRuntimeInput(...)`
|
||||
4. Rewired `assistantLivingChatAttemptRuntimeAdapter` to consume living-chat runtime input builders (behavior-preserving):
|
||||
- `buildExecuteLlmChat(...)` now delegates llm payload assembly via builder;
|
||||
- top-level living-chat handler invocation now uses builder payload.
|
||||
5. Added focused builder tests:
|
||||
- `assistantAddressLaneResponseRuntimeInputBuilder.test.ts`
|
||||
- `assistantLivingChatAttemptRuntimeInputBuilder.test.ts`
|
||||
|
||||
Validation:
|
||||
1. `npm run build` passed.
|
||||
2. Targeted living/address/deep followup pack passed:
|
||||
- `assistantAddressLaneResponseRuntimeInputBuilder.test.ts`
|
||||
- `assistantLivingChatAttemptRuntimeInputBuilder.test.ts`
|
||||
- `assistantAddressLaneResponseAttemptRuntimeAdapter.test.ts`
|
||||
- `assistantLivingChatAttemptRuntimeAdapter.test.ts`
|
||||
- `assistantLivingChatHandlerRuntimeAdapter.test.ts`
|
||||
- `assistantLivingChatRuntimeAdapter.test.ts`
|
||||
- `assistantAddressAttemptRuntimeAdapter.test.ts`
|
||||
- `assistantAddressLaneAttemptRuntimeAdapter.test.ts`
|
||||
- `assistantAddressLaneResponseRuntimeAdapter.test.ts`
|
||||
- `assistantAddressRuntimeAdapter.test.ts`
|
||||
- `assistantDeepTurnAttemptInputBuilder.test.ts`
|
||||
- `assistantDeepTurnAnalysisAttemptInputBuilder.test.ts`
|
||||
- `assistantDeepTurnResponseRuntimeInputBuilder.test.ts`
|
||||
- `assistantDeepTurnAttemptRuntimeAdapter.test.ts`
|
||||
- `assistantDeepTurnAnalysisAttemptRuntimeAdapter.test.ts`
|
||||
- `assistantDeepTurnResponseAttemptRuntimeAdapter.test.ts`
|
||||
- `assistantDeepTurnAnalysisRuntimeAdapter.test.ts`
|
||||
- `assistantDeepTurnResponseRuntimeAdapter.test.ts`
|
||||
- `assistantDeepTurnPackagingRuntimeAdapter.test.ts`
|
||||
- `assistantTurnRuntimeInputBuilder.test.ts`
|
||||
- `assistantTurnAttemptRuntimeAdapter.test.ts`
|
||||
- `assistantTurnRuntimeDepsAdapter.test.ts`
|
||||
- `assistantOrganizationScopeRuntimeAdapter.test.ts`
|
||||
- `assistantWave10SettlementCorrectiveRegression.test.ts`
|
||||
- `assistantLivingChatMode.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 + 2.50 + 2.51 + 2.52 + 2.53 + 2.54 + 2.55 + 2.56 + 2.57 + 2.58 + 2.59 + 2.60 + 2.61 + 2.62 + 2.63 + 2.64 completed)**
|
||||
|
||||
## Stage 3 (P2): Hybrid Semantic Layer (LLM + Deterministic Guards)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@
|
|||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.runAssistantAddressLaneResponseAttemptRuntime = runAssistantAddressLaneResponseAttemptRuntime;
|
||||
const assistantAddressLaneResponseRuntimeAdapter_1 = require("./assistantAddressLaneResponseRuntimeAdapter");
|
||||
const assistantAddressLaneResponseRuntimeInputBuilder_1 = require("./assistantAddressLaneResponseRuntimeInputBuilder");
|
||||
function runAssistantAddressLaneResponseAttemptRuntime(input) {
|
||||
const runAddressLaneResponseRuntimeSafe = input.runAddressLaneResponseRuntime ?? assistantAddressLaneResponseRuntimeAdapter_1.runAssistantAddressLaneResponseRuntime;
|
||||
const runtime = runAddressLaneResponseRuntimeSafe({
|
||||
const runtime = runAddressLaneResponseRuntimeSafe((0, assistantAddressLaneResponseRuntimeInputBuilder_1.buildAssistantAddressLaneResponseRuntimeInput)({
|
||||
sessionId: input.sessionId,
|
||||
userMessage: input.userMessage,
|
||||
effectiveAddressUserMessage: input.effectiveAddressUserMessage,
|
||||
|
|
@ -24,6 +25,6 @@ function runAssistantAddressLaneResponseAttemptRuntime(input) {
|
|||
cloneConversation: input.cloneConversation,
|
||||
logEvent: input.logEvent,
|
||||
messageIdFactory: input.messageIdFactory
|
||||
});
|
||||
}));
|
||||
return runtime.response;
|
||||
}
|
||||
|
|
|
|||
26
llm_normalizer/backend/dist/services/assistantAddressLaneResponseRuntimeInputBuilder.js
vendored
Normal file
26
llm_normalizer/backend/dist/services/assistantAddressLaneResponseRuntimeInputBuilder.js
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.buildAssistantAddressLaneResponseRuntimeInput = buildAssistantAddressLaneResponseRuntimeInput;
|
||||
function buildAssistantAddressLaneResponseRuntimeInput(input) {
|
||||
return {
|
||||
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
|
||||
};
|
||||
}
|
||||
|
|
@ -3,8 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||
exports.runAssistantLivingChatAttemptRuntime = runAssistantLivingChatAttemptRuntime;
|
||||
const assistantLivingChatHandlerRuntimeAdapter_1 = require("./assistantLivingChatHandlerRuntimeAdapter");
|
||||
const assistantLivingChatLlmRuntimeAdapter_1 = require("./assistantLivingChatLlmRuntimeAdapter");
|
||||
const assistantLivingChatAttemptRuntimeInputBuilder_1 = require("./assistantLivingChatAttemptRuntimeInputBuilder");
|
||||
function buildExecuteLlmChat(input, runLivingChatLlmSafe) {
|
||||
return async () => runLivingChatLlmSafe({
|
||||
return async () => runLivingChatLlmSafe((0, assistantLivingChatAttemptRuntimeInputBuilder_1.buildAssistantLivingChatLlmRuntimeInput)({
|
||||
userMessage: input.userMessage,
|
||||
sessionItems: input.sessionItems,
|
||||
payload: input.payload,
|
||||
|
|
@ -14,13 +15,13 @@ function buildExecuteLlmChat(input, runLivingChatLlmSafe) {
|
|||
defaultModel: input.defaultModel,
|
||||
defaultBaseUrl: input.defaultBaseUrl,
|
||||
defaultApiKey: input.defaultApiKey
|
||||
});
|
||||
}));
|
||||
}
|
||||
async function runAssistantLivingChatAttemptRuntime(input) {
|
||||
const runLivingChatHandlerSafe = input.runLivingChatHandler ?? assistantLivingChatHandlerRuntimeAdapter_1.tryHandleAssistantLivingChatRuntime;
|
||||
const runLivingChatLlmSafe = input.runLivingChatLlm ?? assistantLivingChatLlmRuntimeAdapter_1.runAssistantLivingChatLlmRuntime;
|
||||
const executeLlmChat = buildExecuteLlmChat(input, runLivingChatLlmSafe);
|
||||
return runLivingChatHandlerSafe({
|
||||
return runLivingChatHandlerSafe((0, assistantLivingChatAttemptRuntimeInputBuilder_1.buildAssistantLivingChatHandlerRuntimeInput)({
|
||||
sessionId: input.sessionId,
|
||||
userMessage: input.userMessage,
|
||||
sessionItems: input.sessionItems,
|
||||
|
|
@ -58,5 +59,5 @@ async function runAssistantLivingChatAttemptRuntime(input) {
|
|||
nowIso: input.nowIso,
|
||||
runLivingChatRuntime: input.runLivingChatRuntime,
|
||||
finalizeLivingChatTurn: input.finalizeLivingChatTurn
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
|
|
|||
58
llm_normalizer/backend/dist/services/assistantLivingChatAttemptRuntimeInputBuilder.js
vendored
Normal file
58
llm_normalizer/backend/dist/services/assistantLivingChatAttemptRuntimeInputBuilder.js
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.buildAssistantLivingChatLlmRuntimeInput = buildAssistantLivingChatLlmRuntimeInput;
|
||||
exports.buildAssistantLivingChatHandlerRuntimeInput = buildAssistantLivingChatHandlerRuntimeInput;
|
||||
function buildAssistantLivingChatLlmRuntimeInput(input) {
|
||||
return {
|
||||
userMessage: input.userMessage,
|
||||
sessionItems: input.sessionItems,
|
||||
payload: input.payload,
|
||||
chatClient: input.chatClient,
|
||||
loadAssistantCanonExcerpt: input.loadAssistantCanonExcerpt,
|
||||
sanitizeOutgoingAssistantText: input.sanitizeOutgoingAssistantText,
|
||||
defaultModel: input.defaultModel,
|
||||
defaultBaseUrl: input.defaultBaseUrl,
|
||||
defaultApiKey: input.defaultApiKey
|
||||
};
|
||||
}
|
||||
function buildAssistantLivingChatHandlerRuntimeInput(input) {
|
||||
return {
|
||||
sessionId: input.sessionId,
|
||||
userMessage: input.userMessage,
|
||||
sessionItems: input.sessionItems,
|
||||
modeDecision: input.modeDecision,
|
||||
sessionScope: input.sessionScope,
|
||||
addressRuntimeMeta: input.addressRuntimeMeta,
|
||||
traceIdFactory: input.traceIdFactory,
|
||||
toNonEmptyString: input.toNonEmptyString,
|
||||
mergeKnownOrganizations: input.mergeKnownOrganizations,
|
||||
hasAssistantDataScopeMetaQuestionSignal: input.hasAssistantDataScopeMetaQuestionSignal,
|
||||
shouldHandleAsAssistantCapabilityMetaQuery: input.shouldHandleAsAssistantCapabilityMetaQuery,
|
||||
hasDestructiveDataActionSignal: input.hasDestructiveDataActionSignal,
|
||||
hasDangerOrCoercionSignal: input.hasDangerOrCoercionSignal,
|
||||
hasOperationalAdminActionRequestSignal: input.hasOperationalAdminActionRequestSignal,
|
||||
hasOrganizationFactLookupSignal: input.hasOrganizationFactLookupSignal,
|
||||
hasOrganizationFactFollowupSignal: input.hasOrganizationFactFollowupSignal,
|
||||
shouldEmitOrganizationSelectionReply: input.shouldEmitOrganizationSelectionReply,
|
||||
hasAssistantCapabilityQuestionSignal: input.hasAssistantCapabilityQuestionSignal,
|
||||
resolveDataScopeProbe: input.resolveDataScopeProbe,
|
||||
executeLlmChat: input.executeLlmChat,
|
||||
applyScriptGuard: input.applyScriptGuard,
|
||||
applyGroundingGuard: input.applyGroundingGuard,
|
||||
buildAssistantSafetyRefusalReply: input.buildAssistantSafetyRefusalReply,
|
||||
buildAssistantDataScopeContractReply: input.buildAssistantDataScopeContractReply,
|
||||
buildAssistantOrganizationFactBoundaryReply: input.buildAssistantOrganizationFactBoundaryReply,
|
||||
buildAssistantDataScopeSelectionReply: input.buildAssistantDataScopeSelectionReply,
|
||||
buildAssistantOperationalBoundaryReply: input.buildAssistantOperationalBoundaryReply,
|
||||
buildAssistantCapabilityContractReply: input.buildAssistantCapabilityContractReply,
|
||||
appendItem: input.appendItem,
|
||||
getSession: input.getSession,
|
||||
persistSession: input.persistSession,
|
||||
cloneConversation: input.cloneConversation,
|
||||
logEvent: input.logEvent,
|
||||
messageIdFactory: input.messageIdFactory,
|
||||
nowIso: input.nowIso,
|
||||
runLivingChatRuntime: input.runLivingChatRuntime,
|
||||
finalizeLivingChatTurn: input.finalizeLivingChatTurn
|
||||
};
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import {
|
|||
type RunAssistantAddressLaneResponseRuntimeInput,
|
||||
type RunAssistantAddressLaneResponseRuntimeOutput
|
||||
} from "./assistantAddressLaneResponseRuntimeAdapter";
|
||||
import { buildAssistantAddressLaneResponseRuntimeInput } from "./assistantAddressLaneResponseRuntimeInputBuilder";
|
||||
|
||||
export interface RunAssistantAddressLaneResponseAttemptRuntimeInput<
|
||||
ResponseType = AssistantMessageResponsePayload
|
||||
|
|
@ -20,26 +21,28 @@ export function runAssistantAddressLaneResponseAttemptRuntime<
|
|||
): 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
|
||||
});
|
||||
const runtime = runAddressLaneResponseRuntimeSafe(
|
||||
buildAssistantAddressLaneResponseRuntimeInput({
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
import type { RunAssistantAddressLaneResponseRuntimeInput } from "./assistantAddressLaneResponseRuntimeAdapter";
|
||||
|
||||
export interface BuildAssistantAddressLaneResponseRuntimeInputInput<ResponseType = unknown> {
|
||||
sessionId: RunAssistantAddressLaneResponseRuntimeInput<ResponseType>["sessionId"];
|
||||
userMessage: RunAssistantAddressLaneResponseRuntimeInput<ResponseType>["userMessage"];
|
||||
effectiveAddressUserMessage:
|
||||
RunAssistantAddressLaneResponseRuntimeInput<ResponseType>["effectiveAddressUserMessage"];
|
||||
addressLane: RunAssistantAddressLaneResponseRuntimeInput<ResponseType>["addressLane"];
|
||||
carryoverMeta?: RunAssistantAddressLaneResponseRuntimeInput<ResponseType>["carryoverMeta"];
|
||||
llmPreDecomposeMeta?: RunAssistantAddressLaneResponseRuntimeInput<ResponseType>["llmPreDecomposeMeta"];
|
||||
knownOrganizations: RunAssistantAddressLaneResponseRuntimeInput<ResponseType>["knownOrganizations"];
|
||||
activeOrganization: RunAssistantAddressLaneResponseRuntimeInput<ResponseType>["activeOrganization"];
|
||||
sanitizeOutgoingAssistantText:
|
||||
RunAssistantAddressLaneResponseRuntimeInput<ResponseType>["sanitizeOutgoingAssistantText"];
|
||||
buildAddressDebugPayload:
|
||||
RunAssistantAddressLaneResponseRuntimeInput<ResponseType>["buildAddressDebugPayload"];
|
||||
buildAddressFollowupOffer:
|
||||
RunAssistantAddressLaneResponseRuntimeInput<ResponseType>["buildAddressFollowupOffer"];
|
||||
mergeKnownOrganizations:
|
||||
RunAssistantAddressLaneResponseRuntimeInput<ResponseType>["mergeKnownOrganizations"];
|
||||
toNonEmptyString: RunAssistantAddressLaneResponseRuntimeInput<ResponseType>["toNonEmptyString"];
|
||||
appendItem: RunAssistantAddressLaneResponseRuntimeInput<ResponseType>["appendItem"];
|
||||
getSession: RunAssistantAddressLaneResponseRuntimeInput<ResponseType>["getSession"];
|
||||
persistSession: RunAssistantAddressLaneResponseRuntimeInput<ResponseType>["persistSession"];
|
||||
cloneConversation: RunAssistantAddressLaneResponseRuntimeInput<ResponseType>["cloneConversation"];
|
||||
logEvent: RunAssistantAddressLaneResponseRuntimeInput<ResponseType>["logEvent"];
|
||||
messageIdFactory: RunAssistantAddressLaneResponseRuntimeInput<ResponseType>["messageIdFactory"];
|
||||
}
|
||||
|
||||
export function buildAssistantAddressLaneResponseRuntimeInput<ResponseType = unknown>(
|
||||
input: BuildAssistantAddressLaneResponseRuntimeInputInput<ResponseType>
|
||||
): RunAssistantAddressLaneResponseRuntimeInput<ResponseType> {
|
||||
return {
|
||||
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
|
||||
};
|
||||
}
|
||||
|
|
@ -6,6 +6,10 @@ import {
|
|||
runAssistantLivingChatLlmRuntime,
|
||||
type RunAssistantLivingChatLlmRuntimeInput
|
||||
} from "./assistantLivingChatLlmRuntimeAdapter";
|
||||
import {
|
||||
buildAssistantLivingChatHandlerRuntimeInput,
|
||||
buildAssistantLivingChatLlmRuntimeInput
|
||||
} from "./assistantLivingChatAttemptRuntimeInputBuilder";
|
||||
|
||||
type AssistantLivingChatHandlerInput<ResponseType> = TryHandleAssistantLivingChatRuntimeInput<ResponseType>;
|
||||
type AssistantLivingChatLlmInput = RunAssistantLivingChatLlmRuntimeInput;
|
||||
|
|
@ -32,17 +36,19 @@ function buildExecuteLlmChat<ResponseType>(
|
|||
runLivingChatLlmSafe: (input: AssistantLivingChatLlmInput) => Promise<string>
|
||||
): AssistantLivingChatHandlerInput<ResponseType>["executeLlmChat"] {
|
||||
return async () =>
|
||||
runLivingChatLlmSafe({
|
||||
userMessage: input.userMessage,
|
||||
sessionItems: input.sessionItems,
|
||||
payload: input.payload,
|
||||
chatClient: input.chatClient,
|
||||
loadAssistantCanonExcerpt: input.loadAssistantCanonExcerpt,
|
||||
sanitizeOutgoingAssistantText: input.sanitizeOutgoingAssistantText,
|
||||
defaultModel: input.defaultModel,
|
||||
defaultBaseUrl: input.defaultBaseUrl,
|
||||
defaultApiKey: input.defaultApiKey
|
||||
});
|
||||
runLivingChatLlmSafe(
|
||||
buildAssistantLivingChatLlmRuntimeInput({
|
||||
userMessage: input.userMessage,
|
||||
sessionItems: input.sessionItems,
|
||||
payload: input.payload,
|
||||
chatClient: input.chatClient,
|
||||
loadAssistantCanonExcerpt: input.loadAssistantCanonExcerpt,
|
||||
sanitizeOutgoingAssistantText: input.sanitizeOutgoingAssistantText,
|
||||
defaultModel: input.defaultModel,
|
||||
defaultBaseUrl: input.defaultBaseUrl,
|
||||
defaultApiKey: input.defaultApiKey
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
export async function runAssistantLivingChatAttemptRuntime<ResponseType = unknown>(
|
||||
|
|
@ -51,43 +57,45 @@ export async function runAssistantLivingChatAttemptRuntime<ResponseType = unknow
|
|||
const runLivingChatHandlerSafe = input.runLivingChatHandler ?? tryHandleAssistantLivingChatRuntime;
|
||||
const runLivingChatLlmSafe = input.runLivingChatLlm ?? runAssistantLivingChatLlmRuntime;
|
||||
const executeLlmChat = buildExecuteLlmChat(input, runLivingChatLlmSafe);
|
||||
return runLivingChatHandlerSafe({
|
||||
sessionId: input.sessionId,
|
||||
userMessage: input.userMessage,
|
||||
sessionItems: input.sessionItems,
|
||||
modeDecision: input.modeDecision,
|
||||
sessionScope: input.sessionScope,
|
||||
addressRuntimeMeta: input.addressRuntimeMeta,
|
||||
traceIdFactory: input.traceIdFactory,
|
||||
toNonEmptyString: input.toNonEmptyString,
|
||||
mergeKnownOrganizations: input.mergeKnownOrganizations,
|
||||
hasAssistantDataScopeMetaQuestionSignal: input.hasAssistantDataScopeMetaQuestionSignal,
|
||||
shouldHandleAsAssistantCapabilityMetaQuery: input.shouldHandleAsAssistantCapabilityMetaQuery,
|
||||
hasDestructiveDataActionSignal: input.hasDestructiveDataActionSignal,
|
||||
hasDangerOrCoercionSignal: input.hasDangerOrCoercionSignal,
|
||||
hasOperationalAdminActionRequestSignal: input.hasOperationalAdminActionRequestSignal,
|
||||
hasOrganizationFactLookupSignal: input.hasOrganizationFactLookupSignal,
|
||||
hasOrganizationFactFollowupSignal: input.hasOrganizationFactFollowupSignal,
|
||||
shouldEmitOrganizationSelectionReply: input.shouldEmitOrganizationSelectionReply,
|
||||
hasAssistantCapabilityQuestionSignal: input.hasAssistantCapabilityQuestionSignal,
|
||||
resolveDataScopeProbe: input.resolveDataScopeProbe,
|
||||
executeLlmChat,
|
||||
applyScriptGuard: input.applyScriptGuard,
|
||||
applyGroundingGuard: input.applyGroundingGuard,
|
||||
buildAssistantSafetyRefusalReply: input.buildAssistantSafetyRefusalReply,
|
||||
buildAssistantDataScopeContractReply: input.buildAssistantDataScopeContractReply,
|
||||
buildAssistantOrganizationFactBoundaryReply: input.buildAssistantOrganizationFactBoundaryReply,
|
||||
buildAssistantDataScopeSelectionReply: input.buildAssistantDataScopeSelectionReply,
|
||||
buildAssistantOperationalBoundaryReply: input.buildAssistantOperationalBoundaryReply,
|
||||
buildAssistantCapabilityContractReply: input.buildAssistantCapabilityContractReply,
|
||||
appendItem: input.appendItem,
|
||||
getSession: input.getSession,
|
||||
persistSession: input.persistSession,
|
||||
cloneConversation: input.cloneConversation,
|
||||
logEvent: input.logEvent,
|
||||
messageIdFactory: input.messageIdFactory,
|
||||
nowIso: input.nowIso,
|
||||
runLivingChatRuntime: input.runLivingChatRuntime,
|
||||
finalizeLivingChatTurn: input.finalizeLivingChatTurn
|
||||
});
|
||||
return runLivingChatHandlerSafe(
|
||||
buildAssistantLivingChatHandlerRuntimeInput({
|
||||
sessionId: input.sessionId,
|
||||
userMessage: input.userMessage,
|
||||
sessionItems: input.sessionItems,
|
||||
modeDecision: input.modeDecision,
|
||||
sessionScope: input.sessionScope,
|
||||
addressRuntimeMeta: input.addressRuntimeMeta,
|
||||
traceIdFactory: input.traceIdFactory,
|
||||
toNonEmptyString: input.toNonEmptyString,
|
||||
mergeKnownOrganizations: input.mergeKnownOrganizations,
|
||||
hasAssistantDataScopeMetaQuestionSignal: input.hasAssistantDataScopeMetaQuestionSignal,
|
||||
shouldHandleAsAssistantCapabilityMetaQuery: input.shouldHandleAsAssistantCapabilityMetaQuery,
|
||||
hasDestructiveDataActionSignal: input.hasDestructiveDataActionSignal,
|
||||
hasDangerOrCoercionSignal: input.hasDangerOrCoercionSignal,
|
||||
hasOperationalAdminActionRequestSignal: input.hasOperationalAdminActionRequestSignal,
|
||||
hasOrganizationFactLookupSignal: input.hasOrganizationFactLookupSignal,
|
||||
hasOrganizationFactFollowupSignal: input.hasOrganizationFactFollowupSignal,
|
||||
shouldEmitOrganizationSelectionReply: input.shouldEmitOrganizationSelectionReply,
|
||||
hasAssistantCapabilityQuestionSignal: input.hasAssistantCapabilityQuestionSignal,
|
||||
resolveDataScopeProbe: input.resolveDataScopeProbe,
|
||||
executeLlmChat,
|
||||
applyScriptGuard: input.applyScriptGuard,
|
||||
applyGroundingGuard: input.applyGroundingGuard,
|
||||
buildAssistantSafetyRefusalReply: input.buildAssistantSafetyRefusalReply,
|
||||
buildAssistantDataScopeContractReply: input.buildAssistantDataScopeContractReply,
|
||||
buildAssistantOrganizationFactBoundaryReply: input.buildAssistantOrganizationFactBoundaryReply,
|
||||
buildAssistantDataScopeSelectionReply: input.buildAssistantDataScopeSelectionReply,
|
||||
buildAssistantOperationalBoundaryReply: input.buildAssistantOperationalBoundaryReply,
|
||||
buildAssistantCapabilityContractReply: input.buildAssistantCapabilityContractReply,
|
||||
appendItem: input.appendItem,
|
||||
getSession: input.getSession,
|
||||
persistSession: input.persistSession,
|
||||
cloneConversation: input.cloneConversation,
|
||||
logEvent: input.logEvent,
|
||||
messageIdFactory: input.messageIdFactory,
|
||||
nowIso: input.nowIso,
|
||||
runLivingChatRuntime: input.runLivingChatRuntime,
|
||||
finalizeLivingChatTurn: input.finalizeLivingChatTurn
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,81 @@
|
|||
import type {
|
||||
TryHandleAssistantLivingChatRuntimeInput
|
||||
} from "./assistantLivingChatHandlerRuntimeAdapter";
|
||||
import type { RunAssistantLivingChatLlmRuntimeInput } from "./assistantLivingChatLlmRuntimeAdapter";
|
||||
|
||||
export interface BuildAssistantLivingChatLlmRuntimeInputInput {
|
||||
userMessage: RunAssistantLivingChatLlmRuntimeInput["userMessage"];
|
||||
sessionItems: RunAssistantLivingChatLlmRuntimeInput["sessionItems"];
|
||||
payload: RunAssistantLivingChatLlmRuntimeInput["payload"];
|
||||
chatClient: RunAssistantLivingChatLlmRuntimeInput["chatClient"];
|
||||
loadAssistantCanonExcerpt: RunAssistantLivingChatLlmRuntimeInput["loadAssistantCanonExcerpt"];
|
||||
sanitizeOutgoingAssistantText: RunAssistantLivingChatLlmRuntimeInput["sanitizeOutgoingAssistantText"];
|
||||
defaultModel: RunAssistantLivingChatLlmRuntimeInput["defaultModel"];
|
||||
defaultBaseUrl: RunAssistantLivingChatLlmRuntimeInput["defaultBaseUrl"];
|
||||
defaultApiKey?: RunAssistantLivingChatLlmRuntimeInput["defaultApiKey"];
|
||||
}
|
||||
|
||||
export function buildAssistantLivingChatLlmRuntimeInput(
|
||||
input: BuildAssistantLivingChatLlmRuntimeInputInput
|
||||
): RunAssistantLivingChatLlmRuntimeInput {
|
||||
return {
|
||||
userMessage: input.userMessage,
|
||||
sessionItems: input.sessionItems,
|
||||
payload: input.payload,
|
||||
chatClient: input.chatClient,
|
||||
loadAssistantCanonExcerpt: input.loadAssistantCanonExcerpt,
|
||||
sanitizeOutgoingAssistantText: input.sanitizeOutgoingAssistantText,
|
||||
defaultModel: input.defaultModel,
|
||||
defaultBaseUrl: input.defaultBaseUrl,
|
||||
defaultApiKey: input.defaultApiKey
|
||||
};
|
||||
}
|
||||
|
||||
export interface BuildAssistantLivingChatHandlerRuntimeInputInput<ResponseType = unknown>
|
||||
extends Omit<TryHandleAssistantLivingChatRuntimeInput<ResponseType>, "executeLlmChat"> {
|
||||
executeLlmChat: TryHandleAssistantLivingChatRuntimeInput<ResponseType>["executeLlmChat"];
|
||||
}
|
||||
|
||||
export function buildAssistantLivingChatHandlerRuntimeInput<ResponseType = unknown>(
|
||||
input: BuildAssistantLivingChatHandlerRuntimeInputInput<ResponseType>
|
||||
): TryHandleAssistantLivingChatRuntimeInput<ResponseType> {
|
||||
return {
|
||||
sessionId: input.sessionId,
|
||||
userMessage: input.userMessage,
|
||||
sessionItems: input.sessionItems,
|
||||
modeDecision: input.modeDecision,
|
||||
sessionScope: input.sessionScope,
|
||||
addressRuntimeMeta: input.addressRuntimeMeta,
|
||||
traceIdFactory: input.traceIdFactory,
|
||||
toNonEmptyString: input.toNonEmptyString,
|
||||
mergeKnownOrganizations: input.mergeKnownOrganizations,
|
||||
hasAssistantDataScopeMetaQuestionSignal: input.hasAssistantDataScopeMetaQuestionSignal,
|
||||
shouldHandleAsAssistantCapabilityMetaQuery: input.shouldHandleAsAssistantCapabilityMetaQuery,
|
||||
hasDestructiveDataActionSignal: input.hasDestructiveDataActionSignal,
|
||||
hasDangerOrCoercionSignal: input.hasDangerOrCoercionSignal,
|
||||
hasOperationalAdminActionRequestSignal: input.hasOperationalAdminActionRequestSignal,
|
||||
hasOrganizationFactLookupSignal: input.hasOrganizationFactLookupSignal,
|
||||
hasOrganizationFactFollowupSignal: input.hasOrganizationFactFollowupSignal,
|
||||
shouldEmitOrganizationSelectionReply: input.shouldEmitOrganizationSelectionReply,
|
||||
hasAssistantCapabilityQuestionSignal: input.hasAssistantCapabilityQuestionSignal,
|
||||
resolveDataScopeProbe: input.resolveDataScopeProbe,
|
||||
executeLlmChat: input.executeLlmChat,
|
||||
applyScriptGuard: input.applyScriptGuard,
|
||||
applyGroundingGuard: input.applyGroundingGuard,
|
||||
buildAssistantSafetyRefusalReply: input.buildAssistantSafetyRefusalReply,
|
||||
buildAssistantDataScopeContractReply: input.buildAssistantDataScopeContractReply,
|
||||
buildAssistantOrganizationFactBoundaryReply: input.buildAssistantOrganizationFactBoundaryReply,
|
||||
buildAssistantDataScopeSelectionReply: input.buildAssistantDataScopeSelectionReply,
|
||||
buildAssistantOperationalBoundaryReply: input.buildAssistantOperationalBoundaryReply,
|
||||
buildAssistantCapabilityContractReply: input.buildAssistantCapabilityContractReply,
|
||||
appendItem: input.appendItem,
|
||||
getSession: input.getSession,
|
||||
persistSession: input.persistSession,
|
||||
cloneConversation: input.cloneConversation,
|
||||
logEvent: input.logEvent,
|
||||
messageIdFactory: input.messageIdFactory,
|
||||
nowIso: input.nowIso,
|
||||
runLivingChatRuntime: input.runLivingChatRuntime,
|
||||
finalizeLivingChatTurn: input.finalizeLivingChatTurn
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
import { describe, expect, it, vi } from "vitest";
|
||||
import { buildAssistantAddressLaneResponseRuntimeInput } from "../src/services/assistantAddressLaneResponseRuntimeInputBuilder";
|
||||
|
||||
function buildInput(overrides: Record<string, unknown> = {}) {
|
||||
return {
|
||||
sessionId: "asst-1",
|
||||
userMessage: "where is settlement tail",
|
||||
effectiveAddressUserMessage: "where is settlement tail for Org A",
|
||||
addressLane: {
|
||||
reply_text: "address reply",
|
||||
reply_type: "factual_with_explanation",
|
||||
debug: {}
|
||||
},
|
||||
carryoverMeta: { previousReplyType: "partial_coverage" },
|
||||
llmPreDecomposeMeta: { mode: "supported", confidence: "high" },
|
||||
knownOrganizations: ["Org A"],
|
||||
activeOrganization: "Org A",
|
||||
sanitizeOutgoingAssistantText: vi.fn((value: unknown, fallback = "") => {
|
||||
const text = String(value ?? "").trim();
|
||||
return text || fallback;
|
||||
}),
|
||||
buildAddressDebugPayload: vi.fn(() => ({})),
|
||||
buildAddressFollowupOffer: vi.fn(() => null),
|
||||
mergeKnownOrganizations: vi.fn((values: string[]) => values),
|
||||
toNonEmptyString: vi.fn((value: unknown) =>
|
||||
typeof value === "string" && value.trim().length > 0 ? value.trim() : null
|
||||
),
|
||||
appendItem: vi.fn(),
|
||||
getSession: vi.fn(),
|
||||
persistSession: vi.fn(),
|
||||
cloneConversation: vi.fn((items: unknown[]) => items),
|
||||
logEvent: vi.fn(),
|
||||
messageIdFactory: vi.fn(() => "msg-1"),
|
||||
...overrides
|
||||
} as any;
|
||||
}
|
||||
|
||||
describe("assistant address lane response runtime input builder", () => {
|
||||
it("maps lane-response fields into runtime input", () => {
|
||||
const runtimeInput = buildAssistantAddressLaneResponseRuntimeInput(buildInput());
|
||||
|
||||
expect(runtimeInput.sessionId).toBe("asst-1");
|
||||
expect(runtimeInput.effectiveAddressUserMessage).toBe("where is settlement tail for Org A");
|
||||
expect(runtimeInput.knownOrganizations).toEqual(["Org A"]);
|
||||
expect(runtimeInput.carryoverMeta).toEqual({ previousReplyType: "partial_coverage" });
|
||||
expect(runtimeInput.llmPreDecomposeMeta).toEqual({ mode: "supported", confidence: "high" });
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
import { describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
buildAssistantLivingChatHandlerRuntimeInput,
|
||||
buildAssistantLivingChatLlmRuntimeInput
|
||||
} from "../src/services/assistantLivingChatAttemptRuntimeInputBuilder";
|
||||
|
||||
describe("assistant living chat attempt runtime input builder", () => {
|
||||
it("builds living-chat llm runtime input", () => {
|
||||
const runtimeInput = buildAssistantLivingChatLlmRuntimeInput({
|
||||
userMessage: "hello",
|
||||
sessionItems: [{ role: "user", text: "ctx" }],
|
||||
payload: { llmProvider: "openai" } as any,
|
||||
chatClient: {} as any,
|
||||
loadAssistantCanonExcerpt: vi.fn(() => "canon"),
|
||||
sanitizeOutgoingAssistantText: vi.fn((value: unknown) => String(value ?? "")),
|
||||
defaultModel: "gpt-5",
|
||||
defaultBaseUrl: "http://localhost",
|
||||
defaultApiKey: "key"
|
||||
});
|
||||
|
||||
expect(runtimeInput.userMessage).toBe("hello");
|
||||
expect(runtimeInput.sessionItems).toEqual([{ role: "user", text: "ctx" }]);
|
||||
expect(runtimeInput.defaultModel).toBe("gpt-5");
|
||||
expect(runtimeInput.defaultBaseUrl).toBe("http://localhost");
|
||||
expect(runtimeInput.defaultApiKey).toBe("key");
|
||||
});
|
||||
|
||||
it("builds living-chat handler runtime input with execute callback", async () => {
|
||||
const executeLlmChat = vi.fn(async () => "llm-answer");
|
||||
const runtimeInput = buildAssistantLivingChatHandlerRuntimeInput({
|
||||
sessionId: "asst-1",
|
||||
userMessage: "hello",
|
||||
sessionItems: [],
|
||||
modeDecision: { mode: "chat", reason: "living_chat_signal_detected" },
|
||||
sessionScope: { knownOrganizations: [], selectedOrganization: null, activeOrganization: null },
|
||||
addressRuntimeMeta: null,
|
||||
traceIdFactory: vi.fn(() => "chat-1"),
|
||||
toNonEmptyString: vi.fn((value: unknown) =>
|
||||
typeof value === "string" && value.trim().length > 0 ? value.trim() : null
|
||||
),
|
||||
mergeKnownOrganizations: vi.fn((values: string[]) => values),
|
||||
hasAssistantDataScopeMetaQuestionSignal: vi.fn(() => false),
|
||||
shouldHandleAsAssistantCapabilityMetaQuery: vi.fn(() => false),
|
||||
hasDestructiveDataActionSignal: vi.fn(() => false),
|
||||
hasDangerOrCoercionSignal: vi.fn(() => false),
|
||||
hasOperationalAdminActionRequestSignal: vi.fn(() => false),
|
||||
hasOrganizationFactLookupSignal: vi.fn(() => false),
|
||||
hasOrganizationFactFollowupSignal: vi.fn(() => false),
|
||||
shouldEmitOrganizationSelectionReply: vi.fn(() => false),
|
||||
hasAssistantCapabilityQuestionSignal: vi.fn(() => false),
|
||||
resolveDataScopeProbe: vi.fn(async () => null),
|
||||
executeLlmChat,
|
||||
applyScriptGuard: vi.fn((text: string) => ({ text, applied: false, reason: null })),
|
||||
applyGroundingGuard: vi.fn((payload: { chatText: string }) => ({
|
||||
text: payload.chatText,
|
||||
applied: false,
|
||||
reason: null
|
||||
})),
|
||||
buildAssistantSafetyRefusalReply: vi.fn(() => "safety"),
|
||||
buildAssistantDataScopeContractReply: vi.fn(() => "scope"),
|
||||
buildAssistantOrganizationFactBoundaryReply: vi.fn(() => "boundary"),
|
||||
buildAssistantDataScopeSelectionReply: vi.fn(() => "selection"),
|
||||
buildAssistantOperationalBoundaryReply: vi.fn(() => "operational"),
|
||||
buildAssistantCapabilityContractReply: vi.fn(() => "capability"),
|
||||
appendItem: vi.fn(),
|
||||
getSession: vi.fn(),
|
||||
persistSession: vi.fn(),
|
||||
cloneConversation: vi.fn((items: unknown[]) => items),
|
||||
logEvent: vi.fn(),
|
||||
messageIdFactory: vi.fn(() => "msg-1"),
|
||||
nowIso: vi.fn(() => "2026-04-11T00:00:00.000Z"),
|
||||
runLivingChatRuntime: vi.fn(async () => null),
|
||||
finalizeLivingChatTurn: vi.fn()
|
||||
});
|
||||
|
||||
await runtimeInput.executeLlmChat();
|
||||
expect(executeLlmChat).toHaveBeenCalledTimes(1);
|
||||
expect(runtimeInput.modeDecision).toEqual({
|
||||
mode: "chat",
|
||||
reason: "living_chat_signal_detected"
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue