NODEDC_1C/llm_normalizer/backend/src/services/assistantDeepTurnNormalizat...

113 lines
4.2 KiB
TypeScript

import type { AssistantMessageRequestPayload } from "../types/assistant";
import type { NormalizeRequestPayload, NormalizeResponsePayload } from "../types/normalizer";
import type { InvestigationStateWithProblemUnits } from "../types/stage2ProblemUnits";
import type { AssistantFollowupUsage } from "./assistantFollowupUsage";
import { toRouteHintSummary } from "./routeHintAdapter";
export interface AssistantDeepTurnFollowupBinding {
normalizedQuestion: string;
mergedContext: NormalizeRequestPayload["context"] | undefined;
usage: AssistantFollowupUsage | null;
}
export interface BuildAssistantDeepTurnNormalizationRuntimeInput {
userMessage: string;
payload: AssistantMessageRequestPayload;
featureInvestigationStateV1: boolean;
featureStateFollowupBindingV1: boolean;
sessionInvestigationState: InvestigationStateWithProblemUnits | null | undefined;
buildFollowupStateBinding: (input: {
userMessage: string;
payloadContext: NormalizeRequestPayload["context"] | undefined;
investigationState: InvestigationStateWithProblemUnits;
}) => AssistantDeepTurnFollowupBinding;
normalize: (payload: NormalizeRequestPayload) => Promise<NormalizeResponsePayload>;
}
export interface BuildAssistantDeepTurnNormalizationRuntimeOutput {
followupBinding: AssistantDeepTurnFollowupBinding;
normalizePayload: NormalizeRequestPayload;
normalized: NormalizeResponsePayload;
}
function resolveDeepTurnNormalizerPromptVersion(promptVersion: NormalizeRequestPayload["promptVersion"]): string {
const normalized = String(promptVersion ?? "").trim().toLowerCase();
if (
normalized === "normalizer_v2_0_2" ||
normalized === "normalizer_v2_0_1" ||
normalized === "normalizer_v2" ||
normalized === "normalizer_v1"
) {
return String(promptVersion);
}
return "normalizer_v2_0_2";
}
function canSynthesizeRouteSummary(normalized: NormalizeResponsePayload["normalized"]): boolean {
if (!normalized || typeof normalized !== "object") {
return false;
}
const source = normalized as unknown as Record<string, unknown>;
return Array.isArray(source.fragments);
}
export async function buildAssistantDeepTurnNormalizationRuntime(
input: BuildAssistantDeepTurnNormalizationRuntimeInput
): Promise<BuildAssistantDeepTurnNormalizationRuntimeOutput> {
const investigationState = input.sessionInvestigationState;
const canUseFollowupBinding =
input.featureInvestigationStateV1 &&
input.featureStateFollowupBindingV1 &&
investigationState !== null &&
investigationState !== undefined;
const followupBinding =
canUseFollowupBinding
? input.buildFollowupStateBinding({
userMessage: input.userMessage,
payloadContext: input.payload.context,
investigationState
})
: {
normalizedQuestion: input.userMessage,
mergedContext: input.payload.context,
usage: null
};
const normalizePayload: NormalizeRequestPayload = {
llmProvider: input.payload.llmProvider,
apiKey: input.payload.apiKey,
model: input.payload.model,
baseUrl: input.payload.baseUrl,
temperature: input.payload.temperature,
maxOutputTokens: input.payload.maxOutputTokens,
promptVersion: resolveDeepTurnNormalizerPromptVersion(input.payload.promptVersion),
schemaVersion: "v2_0_2",
systemPrompt: input.payload.systemPrompt,
developerPrompt: input.payload.developerPrompt,
domainPrompt: input.payload.domainPrompt,
fewShotExamples: input.payload.fewShotExamples,
userQuestion: followupBinding.normalizedQuestion,
context: followupBinding.mergedContext,
useMock: Boolean(input.payload.useMock)
};
const normalized = await input.normalize(normalizePayload);
const normalizedPayload = normalized.normalized;
const synthesizedRouteSummary =
normalized.route_hint_summary ??
(normalizedPayload && canSynthesizeRouteSummary(normalizedPayload) ? toRouteHintSummary(normalizedPayload) : null);
const normalizedWithRouteSummary: NormalizeResponsePayload =
synthesizedRouteSummary === normalized.route_hint_summary
? normalized
: {
...normalized,
route_hint_summary: synthesizedRouteSummary
};
return {
followupBinding,
normalizePayload,
normalized: normalizedWithRouteSummary
};
}