NODEDC_1C/llm_normalizer/backend/src/services/assistantDeepTurnContextRun...

154 lines
5.7 KiB
TypeScript

import type { NormalizeResponsePayload, RouteHintSummary } from "../types/normalizer";
import type { ClaimBoundAnchorAudit } from "./assistantClaimBoundEvidence";
import type { AssistantLiveTemporalHint } from "./assistantDeepTurnRetrievalRuntimeAdapter";
import { isAssistantFollowupApplied, type AssistantFollowupUsage } from "./assistantFollowupUsage";
import type { DomainPolarityGuardAudit, TemporalGuardAudit } from "./assistantRuntimeGuards";
import type { CompanyAnchorSet } from "./companyAnchorResolver";
const KNOWN_P0_DOMAINS = new Set([
"settlements_60_62",
"vat_document_register_book",
"month_close_costs_20_44",
"fixed_asset_amortization"
]);
function toAnalysisContext(
runtimeAnalysisContext: BuildAssistantDeepTurnRuntimeContextInput["runtimeAnalysisContext"]
): AssistantLiveTemporalHint | null {
if (!runtimeAnalysisContext.active) {
return null;
}
return {
as_of_date: runtimeAnalysisContext.as_of_date,
period_from: runtimeAnalysisContext.period_from,
period_to: runtimeAnalysisContext.period_to,
source: runtimeAnalysisContext.source
};
}
export interface BuildAssistantDeepTurnRuntimeContextInput {
userMessage: string;
normalizedPayload: NormalizeResponsePayload["normalized"];
routeSummary: RouteHintSummary | null;
runtimeAnalysisContext: {
active: boolean;
as_of_date: string | null;
period_from: string | null;
period_to: string | null;
source: string | null;
};
followupUsage: AssistantFollowupUsage | null | undefined;
resolveCompanyAnchors: (userMessage: string) => CompanyAnchorSet;
resolveBusinessScopeAlignment: (input: {
userMessage: string;
companyAnchors: CompanyAnchorSet;
normalized: NormalizeResponsePayload["normalized"];
routeSummary: RouteHintSummary | null;
}) => AssistantBusinessScopeResolution;
inferP0DomainFromMessage: (userMessage: string) => string | null;
resolveTemporalGuard: (input: {
userMessage: string;
normalized: NormalizeResponsePayload["normalized"];
companyAnchors: CompanyAnchorSet;
analysisContext: AssistantLiveTemporalHint | null;
}) => TemporalGuardAudit;
resolveDomainPolarityGuard: (input: {
userMessage: string;
companyAnchors: CompanyAnchorSet;
focusDomainHint: string | null;
}) => DomainPolarityGuardAudit;
resolveClaimBoundAnchors: (input: {
userMessage: string;
companyAnchors: CompanyAnchorSet;
focusDomainHint: string | null;
primaryPeriod: ClaimBoundAnchorAudit["primary_period"] | null;
}) => ClaimBoundAnchorAudit;
resolveBusinessScopeFromLiveContext: (input: {
current: AssistantBusinessScopeResolution;
temporalGuard: TemporalGuardAudit;
claimType: string;
focusDomainHint: string | null;
userMessage: string;
companyAnchors: CompanyAnchorSet;
followupApplied: boolean;
}) => AssistantBusinessScopeResolution;
}
export interface AssistantBusinessScopeResolution {
route_summary_resolved: RouteHintSummary | null;
business_scope_raw?: string[];
business_scope_resolved?: string[];
company_grounding_applied?: boolean;
scope_resolution_reason?: string[];
}
export interface BuildAssistantDeepTurnRuntimeContextOutput {
companyAnchors: CompanyAnchorSet;
initialBusinessScopeResolution: AssistantBusinessScopeResolution;
inferredDomainByMessage: string | null;
focusDomainForGuards: string | null;
temporalGuard: TemporalGuardAudit;
domainPolarityGuardInitial: DomainPolarityGuardAudit;
claimAnchorAudit: ClaimBoundAnchorAudit;
businessScopeResolution: AssistantBusinessScopeResolution;
resolvedRouteSummary: RouteHintSummary | null;
liveTemporalHint: AssistantLiveTemporalHint | null;
}
export function buildAssistantDeepTurnRuntimeContext(
input: BuildAssistantDeepTurnRuntimeContextInput
): BuildAssistantDeepTurnRuntimeContextOutput {
const companyAnchors = input.resolveCompanyAnchors(input.userMessage);
const initialBusinessScopeResolution = input.resolveBusinessScopeAlignment({
userMessage: input.userMessage,
companyAnchors,
normalized: input.normalizedPayload,
routeSummary: input.routeSummary
});
const inferredDomainByMessage = input.inferP0DomainFromMessage(input.userMessage);
const focusDomainForGuards =
inferredDomainByMessage && KNOWN_P0_DOMAINS.has(inferredDomainByMessage) ? inferredDomainByMessage : null;
const analysisContext = toAnalysisContext(input.runtimeAnalysisContext);
const temporalGuard = input.resolveTemporalGuard({
userMessage: input.userMessage,
normalized: input.normalizedPayload,
companyAnchors,
analysisContext
});
const domainPolarityGuardInitial = input.resolveDomainPolarityGuard({
userMessage: input.userMessage,
companyAnchors,
focusDomainHint: focusDomainForGuards
});
const claimAnchorAudit = input.resolveClaimBoundAnchors({
userMessage: input.userMessage,
companyAnchors,
focusDomainHint: focusDomainForGuards,
primaryPeriod: temporalGuard.effective_primary_period ?? temporalGuard.primary_period_window
});
const businessScopeResolution = input.resolveBusinessScopeFromLiveContext({
current: initialBusinessScopeResolution,
temporalGuard,
claimType: claimAnchorAudit.claim_type,
focusDomainHint: focusDomainForGuards,
userMessage: input.userMessage,
companyAnchors,
followupApplied: isAssistantFollowupApplied(input.followupUsage)
});
const resolvedRouteSummary = businessScopeResolution.route_summary_resolved;
const liveTemporalHint = toAnalysisContext(input.runtimeAnalysisContext);
return {
companyAnchors,
initialBusinessScopeResolution,
inferredDomainByMessage,
focusDomainForGuards,
temporalGuard,
domainPolarityGuardInitial,
claimAnchorAudit,
businessScopeResolution,
resolvedRouteSummary,
liveTemporalHint
};
}