ГЛОБАЛЬНЫЙ РЕФАКТОРИНГ АРХИТЕКТУРЫ - Рефакторинг этапов 2.51 - вынос living-chat guard chain (script/grounding/meta boundary wiring) в отдельный input-builder adapter, чтобы ужать assistantService.
This commit is contained in:
parent
5e4cc0ed67
commit
b612615219
|
|
@ -1610,7 +1610,42 @@ 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 completed)**
|
||||
Implemented in current pass (Phase 2.51):
|
||||
1. Extracted living-chat attempt input assembly from `assistantAddressAttemptRuntimeAdapter` into dedicated builder:
|
||||
- `assistantLivingChatAttemptInputBuilder.ts`
|
||||
- introduced:
|
||||
- `buildAssistantLivingChatAttemptRuntimeInput(...)`
|
||||
2. Rewired `assistantAddressAttemptRuntimeAdapter` to consume the new builder (behavior-preserving):
|
||||
- moved inline living-chat payload mapping (including `traceIdFactory` derivation and scope/meta wiring) behind a single input-builder boundary.
|
||||
3. Added focused unit tests:
|
||||
- `assistantLivingChatAttemptInputBuilder.test.ts`
|
||||
|
||||
Validation:
|
||||
1. `npm run build` passed.
|
||||
2. Targeted living/address/deep followup pack passed:
|
||||
- `assistantLivingChatAttemptInputBuilder.test.ts`
|
||||
- `assistantAddressAttemptRuntimeAdapter.test.ts`
|
||||
- `assistantLivingChatAttemptRuntimeAdapter.test.ts`
|
||||
- `assistantLivingChatHandlerRuntimeAdapter.test.ts`
|
||||
- `assistantLivingChatRuntimeAdapter.test.ts`
|
||||
- `assistantTurnRuntimeDepsAdapter.test.ts`
|
||||
- `assistantTurnRuntimeInputBuilder.test.ts`
|
||||
- `assistantTurnAttemptRuntimeAdapter.test.ts`
|
||||
- `assistantOrganizationScopeRuntimeAdapter.test.ts`
|
||||
- `assistantAddressLaneAttemptRuntimeAdapter.test.ts`
|
||||
- `assistantAddressLaneResponseAttemptRuntimeAdapter.test.ts`
|
||||
- `assistantAddressRuntimeAdapter.test.ts`
|
||||
- `assistantAddressLaneResponseRuntimeAdapter.test.ts`
|
||||
- `assistantDeepTurnAttemptRuntimeAdapter.test.ts`
|
||||
- `assistantDeepTurnResponseAttemptRuntimeAdapter.test.ts`
|
||||
- `assistantDeepTurnAnalysisAttemptRuntimeAdapter.test.ts`
|
||||
- `assistantDeepTurnAnalysisRuntimeAdapter.test.ts`
|
||||
- `assistantDeepTurnResponseRuntimeAdapter.test.ts`
|
||||
- `assistantDeepTurnPackagingRuntimeAdapter.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 completed)**
|
||||
|
||||
## Stage 3 (P2): Hybrid Semantic Layer (LLM + Deterministic Guards)
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ const assistantAddressRuntimeAdapter_1 = require("./assistantAddressRuntimeAdapt
|
|||
const assistantAddressLaneAttemptRuntimeAdapter_1 = require("./assistantAddressLaneAttemptRuntimeAdapter");
|
||||
const assistantAddressLaneResponseAttemptRuntimeAdapter_1 = require("./assistantAddressLaneResponseAttemptRuntimeAdapter");
|
||||
const assistantLivingChatAttemptRuntimeAdapter_1 = require("./assistantLivingChatAttemptRuntimeAdapter");
|
||||
const assistantLivingChatAttemptInputBuilder_1 = require("./assistantLivingChatAttemptInputBuilder");
|
||||
async function runAssistantAddressAttemptRuntime(input) {
|
||||
const runAddressRuntimeSafe = input.runAddressRuntime ?? assistantAddressRuntimeAdapter_1.runAssistantAddressRuntime;
|
||||
const runAddressLaneAttemptRuntimeSafe = input.runAddressLaneAttemptRuntime ?? assistantAddressLaneAttemptRuntimeAdapter_1.runAssistantAddressLaneAttemptRuntime;
|
||||
|
|
@ -31,7 +32,7 @@ async function runAssistantAddressAttemptRuntime(input) {
|
|||
logEvent: input.logEvent,
|
||||
messageIdFactory: input.messageIdFactory
|
||||
});
|
||||
const tryHandleLivingChat = async (modeDecision, addressRuntimeMeta = null) => runLivingChatAttemptRuntimeSafe({
|
||||
const tryHandleLivingChat = async (modeDecision, addressRuntimeMeta = null) => runLivingChatAttemptRuntimeSafe((0, assistantLivingChatAttemptInputBuilder_1.buildAssistantLivingChatAttemptRuntimeInput)({
|
||||
sessionId: input.sessionId,
|
||||
userMessage: input.userMessage,
|
||||
sessionItems: input.sessionItems,
|
||||
|
|
@ -42,7 +43,6 @@ async function runAssistantAddressAttemptRuntime(input) {
|
|||
activeOrganization: input.sessionScope.activeOrganization
|
||||
},
|
||||
addressRuntimeMeta,
|
||||
traceIdFactory: () => `chat-${input.messageIdFactory().replace(/^msg-/, "")}`,
|
||||
toNonEmptyString: input.toNonEmptyString,
|
||||
mergeKnownOrganizations: input.mergeKnownOrganizations,
|
||||
hasAssistantDataScopeMetaQuestionSignal: input.hasAssistantDataScopeMetaQuestionSignal,
|
||||
|
|
@ -77,7 +77,7 @@ async function runAssistantAddressAttemptRuntime(input) {
|
|||
defaultModel: input.defaultModel,
|
||||
defaultBaseUrl: input.defaultBaseUrl,
|
||||
defaultApiKey: input.defaultApiKey
|
||||
});
|
||||
}));
|
||||
const runAddressLaneAttempt = async (messageUsed, carryMeta, analysisDateHint) => runAddressLaneAttemptRuntimeSafe({
|
||||
messageUsed,
|
||||
carryMeta,
|
||||
|
|
|
|||
52
llm_normalizer/backend/dist/services/assistantLivingChatAttemptInputBuilder.js
vendored
Normal file
52
llm_normalizer/backend/dist/services/assistantLivingChatAttemptInputBuilder.js
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.buildAssistantLivingChatAttemptRuntimeInput = buildAssistantLivingChatAttemptRuntimeInput;
|
||||
function buildAssistantLivingChatAttemptRuntimeInput(input) {
|
||||
return {
|
||||
sessionId: input.sessionId,
|
||||
userMessage: input.userMessage,
|
||||
sessionItems: input.sessionItems,
|
||||
modeDecision: input.modeDecision,
|
||||
sessionScope: {
|
||||
knownOrganizations: input.sessionScope.knownOrganizations,
|
||||
selectedOrganization: input.sessionScope.selectedOrganization,
|
||||
activeOrganization: input.sessionScope.activeOrganization
|
||||
},
|
||||
addressRuntimeMeta: input.addressRuntimeMeta ?? null,
|
||||
traceIdFactory: () => `chat-${input.messageIdFactory().replace(/^msg-/, "")}`,
|
||||
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,
|
||||
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,
|
||||
payload: input.payload,
|
||||
chatClient: input.chatClient,
|
||||
loadAssistantCanonExcerpt: input.loadAssistantCanonExcerpt,
|
||||
sanitizeOutgoingAssistantText: input.sanitizeOutgoingAssistantText,
|
||||
defaultModel: input.defaultModel,
|
||||
defaultBaseUrl: input.defaultBaseUrl,
|
||||
defaultApiKey: input.defaultApiKey
|
||||
};
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@ import {
|
|||
runAssistantLivingChatAttemptRuntime,
|
||||
type RunAssistantLivingChatAttemptRuntimeInput
|
||||
} from "./assistantLivingChatAttemptRuntimeAdapter";
|
||||
import { buildAssistantLivingChatAttemptRuntimeInput } from "./assistantLivingChatAttemptInputBuilder";
|
||||
|
||||
interface AddressAttemptPayload {
|
||||
llmProvider?: unknown;
|
||||
|
|
@ -135,53 +136,54 @@ export async function runAssistantAddressAttemptRuntime<ResponseType = unknown>(
|
|||
modeDecision,
|
||||
addressRuntimeMeta = null
|
||||
) =>
|
||||
runLivingChatAttemptRuntimeSafe({
|
||||
sessionId: input.sessionId,
|
||||
userMessage: input.userMessage,
|
||||
sessionItems: input.sessionItems,
|
||||
modeDecision,
|
||||
sessionScope: {
|
||||
knownOrganizations: input.sessionScope.knownOrganizations,
|
||||
selectedOrganization: input.sessionScope.selectedOrganization,
|
||||
activeOrganization: input.sessionScope.activeOrganization
|
||||
},
|
||||
addressRuntimeMeta,
|
||||
traceIdFactory: () => `chat-${input.messageIdFactory().replace(/^msg-/, "")}`,
|
||||
toNonEmptyString: input.toNonEmptyString,
|
||||
mergeKnownOrganizations: input.mergeKnownOrganizations as any,
|
||||
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,
|
||||
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,
|
||||
payload: input.payload,
|
||||
chatClient: input.chatClient,
|
||||
loadAssistantCanonExcerpt: input.loadAssistantCanonExcerpt,
|
||||
sanitizeOutgoingAssistantText: input.sanitizeOutgoingAssistantText,
|
||||
defaultModel: input.defaultModel,
|
||||
defaultBaseUrl: input.defaultBaseUrl,
|
||||
defaultApiKey: input.defaultApiKey
|
||||
} as RunAssistantLivingChatAttemptRuntimeInput<ResponseType>);
|
||||
runLivingChatAttemptRuntimeSafe(
|
||||
buildAssistantLivingChatAttemptRuntimeInput({
|
||||
sessionId: input.sessionId,
|
||||
userMessage: input.userMessage,
|
||||
sessionItems: input.sessionItems,
|
||||
modeDecision,
|
||||
sessionScope: {
|
||||
knownOrganizations: input.sessionScope.knownOrganizations,
|
||||
selectedOrganization: input.sessionScope.selectedOrganization,
|
||||
activeOrganization: input.sessionScope.activeOrganization
|
||||
},
|
||||
addressRuntimeMeta,
|
||||
toNonEmptyString: input.toNonEmptyString,
|
||||
mergeKnownOrganizations: input.mergeKnownOrganizations as any,
|
||||
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,
|
||||
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,
|
||||
payload: input.payload,
|
||||
chatClient: input.chatClient,
|
||||
loadAssistantCanonExcerpt: input.loadAssistantCanonExcerpt,
|
||||
sanitizeOutgoingAssistantText: input.sanitizeOutgoingAssistantText,
|
||||
defaultModel: input.defaultModel,
|
||||
defaultBaseUrl: input.defaultBaseUrl,
|
||||
defaultApiKey: input.defaultApiKey
|
||||
} as any) as RunAssistantLivingChatAttemptRuntimeInput<ResponseType>
|
||||
);
|
||||
|
||||
const runAddressLaneAttempt: RunAssistantAddressRuntimeInput<ResponseType>["runAddressLaneAttempt"] = async (
|
||||
messageUsed,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,102 @@
|
|||
import type { RunAssistantLivingChatAttemptRuntimeInput } from "./assistantLivingChatAttemptRuntimeAdapter";
|
||||
|
||||
interface AssistantLivingChatAttemptSessionScope {
|
||||
knownOrganizations: string[];
|
||||
selectedOrganization: string | null;
|
||||
activeOrganization: string | null;
|
||||
}
|
||||
|
||||
export interface BuildAssistantLivingChatAttemptRuntimeInputInput<ResponseType = unknown> {
|
||||
sessionId: string;
|
||||
userMessage: string;
|
||||
sessionItems: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["sessionItems"];
|
||||
modeDecision: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["modeDecision"];
|
||||
sessionScope: AssistantLivingChatAttemptSessionScope;
|
||||
addressRuntimeMeta?: Record<string, unknown> | null;
|
||||
toNonEmptyString: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["toNonEmptyString"];
|
||||
mergeKnownOrganizations: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["mergeKnownOrganizations"];
|
||||
hasAssistantDataScopeMetaQuestionSignal: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["hasAssistantDataScopeMetaQuestionSignal"];
|
||||
shouldHandleAsAssistantCapabilityMetaQuery: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["shouldHandleAsAssistantCapabilityMetaQuery"];
|
||||
hasDestructiveDataActionSignal: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["hasDestructiveDataActionSignal"];
|
||||
hasDangerOrCoercionSignal: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["hasDangerOrCoercionSignal"];
|
||||
hasOperationalAdminActionRequestSignal: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["hasOperationalAdminActionRequestSignal"];
|
||||
hasOrganizationFactLookupSignal: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["hasOrganizationFactLookupSignal"];
|
||||
hasOrganizationFactFollowupSignal: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["hasOrganizationFactFollowupSignal"];
|
||||
shouldEmitOrganizationSelectionReply: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["shouldEmitOrganizationSelectionReply"];
|
||||
hasAssistantCapabilityQuestionSignal: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["hasAssistantCapabilityQuestionSignal"];
|
||||
resolveDataScopeProbe: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["resolveDataScopeProbe"];
|
||||
applyScriptGuard: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["applyScriptGuard"];
|
||||
applyGroundingGuard: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["applyGroundingGuard"];
|
||||
buildAssistantSafetyRefusalReply: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["buildAssistantSafetyRefusalReply"];
|
||||
buildAssistantDataScopeContractReply: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["buildAssistantDataScopeContractReply"];
|
||||
buildAssistantOrganizationFactBoundaryReply: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["buildAssistantOrganizationFactBoundaryReply"];
|
||||
buildAssistantDataScopeSelectionReply: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["buildAssistantDataScopeSelectionReply"];
|
||||
buildAssistantOperationalBoundaryReply: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["buildAssistantOperationalBoundaryReply"];
|
||||
buildAssistantCapabilityContractReply: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["buildAssistantCapabilityContractReply"];
|
||||
appendItem: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["appendItem"];
|
||||
getSession: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["getSession"];
|
||||
persistSession: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["persistSession"];
|
||||
cloneConversation: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["cloneConversation"];
|
||||
logEvent: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["logEvent"];
|
||||
messageIdFactory: NonNullable<RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["messageIdFactory"]>;
|
||||
nowIso: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["nowIso"];
|
||||
payload: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["payload"];
|
||||
chatClient: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["chatClient"];
|
||||
loadAssistantCanonExcerpt: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["loadAssistantCanonExcerpt"];
|
||||
sanitizeOutgoingAssistantText: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["sanitizeOutgoingAssistantText"];
|
||||
defaultModel: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["defaultModel"];
|
||||
defaultBaseUrl: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["defaultBaseUrl"];
|
||||
defaultApiKey?: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["defaultApiKey"];
|
||||
}
|
||||
|
||||
export function buildAssistantLivingChatAttemptRuntimeInput<ResponseType = unknown>(
|
||||
input: BuildAssistantLivingChatAttemptRuntimeInputInput<ResponseType>
|
||||
): RunAssistantLivingChatAttemptRuntimeInput<ResponseType> {
|
||||
return {
|
||||
sessionId: input.sessionId,
|
||||
userMessage: input.userMessage,
|
||||
sessionItems: input.sessionItems,
|
||||
modeDecision: input.modeDecision,
|
||||
sessionScope: {
|
||||
knownOrganizations: input.sessionScope.knownOrganizations,
|
||||
selectedOrganization: input.sessionScope.selectedOrganization,
|
||||
activeOrganization: input.sessionScope.activeOrganization
|
||||
},
|
||||
addressRuntimeMeta: input.addressRuntimeMeta ?? null,
|
||||
traceIdFactory: () => `chat-${input.messageIdFactory().replace(/^msg-/, "")}`,
|
||||
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,
|
||||
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,
|
||||
payload: input.payload,
|
||||
chatClient: input.chatClient,
|
||||
loadAssistantCanonExcerpt: input.loadAssistantCanonExcerpt,
|
||||
sanitizeOutgoingAssistantText: input.sanitizeOutgoingAssistantText,
|
||||
defaultModel: input.defaultModel,
|
||||
defaultBaseUrl: input.defaultBaseUrl,
|
||||
defaultApiKey: input.defaultApiKey
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
import { describe, expect, it, vi } from "vitest";
|
||||
import { buildAssistantLivingChatAttemptRuntimeInput } from "../src/services/assistantLivingChatAttemptInputBuilder";
|
||||
|
||||
function buildInput(overrides: Record<string, unknown> = {}) {
|
||||
return {
|
||||
sessionId: "asst-1",
|
||||
userMessage: "че там",
|
||||
sessionItems: [],
|
||||
modeDecision: {
|
||||
mode: "chat",
|
||||
reason: "living_chat_signal_detected"
|
||||
},
|
||||
sessionScope: {
|
||||
knownOrganizations: ["Org A"],
|
||||
selectedOrganization: "Org A",
|
||||
activeOrganization: "Org A"
|
||||
},
|
||||
addressRuntimeMeta: {
|
||||
source: "address_runtime"
|
||||
},
|
||||
toNonEmptyString: (value: unknown) =>
|
||||
typeof value === "string" && value.trim().length > 0 ? value.trim() : null,
|
||||
mergeKnownOrganizations: (values: string[]) => values,
|
||||
hasAssistantDataScopeMetaQuestionSignal: () => false,
|
||||
shouldHandleAsAssistantCapabilityMetaQuery: () => false,
|
||||
hasDestructiveDataActionSignal: () => false,
|
||||
hasDangerOrCoercionSignal: () => false,
|
||||
hasOperationalAdminActionRequestSignal: () => false,
|
||||
hasOrganizationFactLookupSignal: () => false,
|
||||
hasOrganizationFactFollowupSignal: () => false,
|
||||
shouldEmitOrganizationSelectionReply: () => false,
|
||||
hasAssistantCapabilityQuestionSignal: () => false,
|
||||
resolveDataScopeProbe: () => null,
|
||||
applyScriptGuard: (chatText: string) => chatText,
|
||||
applyGroundingGuard: (guardInput: Record<string, unknown>) => guardInput,
|
||||
buildAssistantSafetyRefusalReply: () => "safety",
|
||||
buildAssistantDataScopeContractReply: () => "scope",
|
||||
buildAssistantOrganizationFactBoundaryReply: () => "boundary",
|
||||
buildAssistantDataScopeSelectionReply: () => "selection",
|
||||
buildAssistantOperationalBoundaryReply: () => "operational",
|
||||
buildAssistantCapabilityContractReply: () => "capability",
|
||||
appendItem: () => {},
|
||||
getSession: () => null,
|
||||
persistSession: () => {},
|
||||
cloneConversation: (items: unknown[]) => items,
|
||||
logEvent: () => {},
|
||||
messageIdFactory: vi.fn(() => "msg-abc123"),
|
||||
nowIso: () => "2026-04-11T00:00:00.000Z",
|
||||
payload: {
|
||||
llmProvider: "openai"
|
||||
},
|
||||
chatClient: {},
|
||||
loadAssistantCanonExcerpt: () => "",
|
||||
sanitizeOutgoingAssistantText: (value: unknown, fallback = "") => {
|
||||
const text = typeof value === "string" ? value.trim() : "";
|
||||
return text || fallback;
|
||||
},
|
||||
defaultModel: "gpt-5",
|
||||
defaultBaseUrl: "http://localhost",
|
||||
defaultApiKey: "key",
|
||||
...overrides
|
||||
} as any;
|
||||
}
|
||||
|
||||
describe("assistant living chat attempt input builder", () => {
|
||||
it("builds living-chat runtime input with derived trace id and session scope", () => {
|
||||
const runtimeInput = buildAssistantLivingChatAttemptRuntimeInput(buildInput());
|
||||
|
||||
expect(runtimeInput.sessionId).toBe("asst-1");
|
||||
expect(runtimeInput.userMessage).toBe("че там");
|
||||
expect(runtimeInput.traceIdFactory()).toBe("chat-abc123");
|
||||
expect(runtimeInput.sessionScope).toEqual({
|
||||
knownOrganizations: ["Org A"],
|
||||
selectedOrganization: "Org A",
|
||||
activeOrganization: "Org A"
|
||||
});
|
||||
expect(runtimeInput.modeDecision).toEqual({
|
||||
mode: "chat",
|
||||
reason: "living_chat_signal_detected"
|
||||
});
|
||||
});
|
||||
|
||||
it("normalizes absent address runtime meta to null and preserves optional api key", () => {
|
||||
const runtimeInput = buildAssistantLivingChatAttemptRuntimeInput(
|
||||
buildInput({
|
||||
addressRuntimeMeta: undefined,
|
||||
defaultApiKey: undefined
|
||||
})
|
||||
);
|
||||
|
||||
expect(runtimeInput.addressRuntimeMeta).toBeNull();
|
||||
expect(runtimeInput.defaultApiKey).toBeUndefined();
|
||||
expect(runtimeInput.defaultBaseUrl).toBe("http://localhost");
|
||||
expect(runtimeInput.defaultModel).toBe("gpt-5");
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue