import type { AssistantRequirement, AnswerGroundingCheck, RequirementCoverageReport, UnifiedRetrievalResult } from "../types/assistant"; import type { NormalizeResponsePayload, RouteHintSummary } from "../types/normalizer"; import type { InvestigationStateWithProblemUnits } from "../types/stage2ProblemUnits"; import type { QuestionTypeClass } from "./questionTypeResolver"; import { resolveQuestionType } from "./questionTypeResolver"; import { composeAssistantAnswer } from "./answerComposer"; export interface BuildAssistantDeepTurnCompositionInput { userMessage: string; routeSummary: RouteHintSummary | null; retrievalResults: UnifiedRetrievalResult[]; requirements: AssistantRequirement[]; coverageReport: RequirementCoverageReport; groundingCheck: AnswerGroundingCheck; followupUsage: unknown | null | undefined; investigationState: InvestigationStateWithProblemUnits | null | undefined; companyAnchors: unknown; normalizedPayload: NormalizeResponsePayload["normalized"]; featureAnswerPolicyV11: boolean; featureProblemCentricAnswerV1: boolean; featureLifecycleAnswerV1: boolean; hasExplicitPeriodAnchor: (normalizedPayload: NormalizeResponsePayload["normalized"]) => boolean; resolveQuestionTypeFn?: (input: string) => QuestionTypeClass; composeAssistantAnswerFn?: typeof composeAssistantAnswer; } export interface AssistantDeepTurnCompositionOutput { focusDomainHint: string | null; questionTypeClass: QuestionTypeClass; hasPeriodInCompanyAnchors: boolean; normalizationPeriodExplicit: boolean; composition: ReturnType; } export function buildAssistantDeepTurnComposition( input: BuildAssistantDeepTurnCompositionInput ): AssistantDeepTurnCompositionOutput { const resolveQuestionTypeSafe = input.resolveQuestionTypeFn ?? resolveQuestionType; const composeAssistantAnswerSafe = input.composeAssistantAnswerFn ?? composeAssistantAnswer; const followupApplied = Boolean((input.followupUsage as { applied?: unknown } | null)?.applied); const focusDomainHint = followupApplied ? input.investigationState?.followup_context?.active_domain ?? input.investigationState?.focus.domain ?? null : null; const questionTypeClass = resolveQuestionTypeSafe(input.userMessage); const companyAnchorSet = input.companyAnchors as { dates?: unknown[]; periods?: unknown[]; } | null; const hasPeriodInCompanyAnchors = (Array.isArray(companyAnchorSet?.dates) && companyAnchorSet.dates.some((item) => String(item ?? "").trim().length > 0)) || (Array.isArray(companyAnchorSet?.periods) && companyAnchorSet.periods.some((item) => String(item ?? "").trim().length > 0)); const normalizationPeriodExplicit = input.hasExplicitPeriodAnchor(input.normalizedPayload) || hasPeriodInCompanyAnchors; const composition = composeAssistantAnswerSafe({ userMessage: input.userMessage, routeSummary: input.routeSummary, retrievalResults: input.retrievalResults, requirements: input.requirements, coverageReport: input.coverageReport, groundingCheck: input.groundingCheck, focusDomainHint, questionTypeHint: questionTypeClass, companyAnchors: input.companyAnchors as any, normalizationPeriodExplicit, enableAnswerPolicyV11: input.featureAnswerPolicyV11, enableProblemCentricAnswerV1: input.featureProblemCentricAnswerV1, enableLifecycleAnswerV1: input.featureLifecycleAnswerV1 }); return { focusDomainHint, questionTypeClass, hasPeriodInCompanyAnchors, normalizationPeriodExplicit, composition }; }