"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.cloneInvestigationState = cloneInvestigationState; exports.createEmptyInvestigationState = createEmptyInvestigationState; exports.updateInvestigationState = updateInvestigationState; const stage1Contracts_1 = require("../types/stage1Contracts"); const stage2ProblemUnits_1 = require("../types/stage2ProblemUnits"); function uniqueStrings(values) { return Array.from(new Set(values.map((item) => item.trim()).filter(Boolean))); } function capStrings(values, max) { return uniqueStrings(values).slice(0, max); } function detectAccounts(text) { return capStrings(text.match(/\b\d{2}(?:\.\d{2})?\b/g) ?? [], stage1Contracts_1.INVESTIGATION_MAX_PRIMARY_ACCOUNTS); } function detectPeriod(text) { const monthly = text.match(/\b(20\d{2})[-/.](0[1-9]|1[0-2])\b/); if (monthly) return `${monthly[1]}-${monthly[2]}`; const yearly = text.match(/\b(20\d{2})\b/); if (yearly) return yearly[1]; return null; } function deriveDomain(routeSummary) { if (!routeSummary) return null; if (routeSummary.mode === "legacy_v1") { return routeSummary.route_hint; } const routes = routeSummary.decisions.map((item) => item.route).filter((route) => route !== "no_route"); const uniqueRoutes = uniqueStrings(routes); if (uniqueRoutes.length === 0) { return "no_route"; } return uniqueRoutes.join(","); } function deriveNarrowingStatus(routeSummary, coverageReport) { if (!routeSummary) { return "unknown"; } if (routeSummary.mode === "legacy_v1") { return "not_needed"; } if (routeSummary.fallback.type === "clarification" || coverageReport.clarification_needed_for.length > 0) { return "needs_clarification"; } const hasNoRoute = routeSummary.decisions.some((item) => item.route === "no_route"); if (hasNoRoute) { return "broad_guarded"; } return routeSummary.decisions.length > 1 ? "applied" : "not_needed"; } function deriveQueryModeHint(routeSummary) { if (!routeSummary) { return "investigation_candidate"; } if (routeSummary.mode === "legacy_v1") { return "direct_answer"; } return routeSummary.fallback.type === "none" ? "direct_answer" : "investigation_candidate"; } function collectEvidenceRefs(retrievalResults) { const refs = retrievalResults.flatMap((result) => result.evidence.map((item) => item.evidence_id)); return capStrings(refs, stage1Contracts_1.INVESTIGATION_MAX_EVIDENCE_REFS); } function collectOpenUncertainties(coverageReport, retrievalResults) { const requirementNotes = [ ...coverageReport.requirements_uncovered.map((item) => `uncovered:${item}`), ...coverageReport.requirements_partially_covered.map((item) => `partial:${item}`), ...coverageReport.clarification_needed_for.map((item) => `clarify:${item}`), ...coverageReport.out_of_scope_requirements.map((item) => `out_of_scope:${item}`) ]; const limitationNotes = retrievalResults.flatMap((result) => result.limitations).slice(0, 6); return capStrings([...requirementNotes, ...limitationNotes], stage1Contracts_1.INVESTIGATION_MAX_UNCERTAINTIES); } function normalizeEntityBacklinks(values) { const result = []; const seen = new Set(); for (const item of values) { const entity = String(item.entity ?? "").trim(); const id = String(item.id ?? "").trim(); if (!entity || !id) { continue; } const key = `${entity}::${id}`; if (seen.has(key)) { continue; } seen.add(key); result.push({ entity, id }); } return result; } function collectProblemUnits(retrievalResults) { return retrievalResults.flatMap((result) => result.problem_units ?? []); } function capProblemUnitState(state) { return { active_problem_units: capStrings(state.active_problem_units, stage2ProblemUnits_1.INVESTIGATION_MAX_ACTIVE_PROBLEM_UNITS), resolved_problem_units: capStrings(state.resolved_problem_units, stage2ProblemUnits_1.INVESTIGATION_MAX_RESOLVED_PROBLEM_UNITS), problem_unit_backlinks: state.problem_unit_backlinks .map((item) => ({ problem_unit_id: String(item.problem_unit_id ?? "").trim(), entity_backlinks: normalizeEntityBacklinks(item.entity_backlinks ?? []) })) .filter((item) => Boolean(item.problem_unit_id) && item.entity_backlinks.length > 0) .slice(0, stage2ProblemUnits_1.INVESTIGATION_MAX_PROBLEM_UNIT_BACKLINKS), focus_problem_types: capStrings(state.focus_problem_types.map((item) => String(item)), stage2ProblemUnits_1.INVESTIGATION_MAX_FOCUS_PROBLEM_TYPES) }; } function updateProblemUnitState(previous, retrievalResults) { const previousState = previous.problem_unit_state; const currentProblemUnits = collectProblemUnits(retrievalResults); const currentIds = capStrings(currentProblemUnits.map((item) => String(item.problem_unit_id ?? "")), stage2ProblemUnits_1.INVESTIGATION_MAX_ACTIVE_PROBLEM_UNITS); const currentTypes = capStrings(currentProblemUnits.map((item) => String(item.problem_unit_type ?? "")), stage2ProblemUnits_1.INVESTIGATION_MAX_FOCUS_PROBLEM_TYPES); const currentBacklinksRaw = currentProblemUnits .filter((item) => currentIds.includes(item.problem_unit_id)) .map((item) => ({ problem_unit_id: item.problem_unit_id, entity_backlinks: normalizeEntityBacklinks(item.entity_backlinks ?? []) })) .filter((item) => item.entity_backlinks.length > 0); const currentBacklinksById = new Map(currentBacklinksRaw.map((item) => [item.problem_unit_id, item.entity_backlinks])); const previousBacklinksById = new Map((previousState?.problem_unit_backlinks ?? []).map((item) => [item.problem_unit_id, item.entity_backlinks])); const active_problem_units = currentIds.length > 0 ? currentIds : capStrings(previousState?.active_problem_units ?? [], stage2ProblemUnits_1.INVESTIGATION_MAX_ACTIVE_PROBLEM_UNITS); const resolved_problem_units = currentIds.length > 0 ? capStrings([ ...(previousState?.active_problem_units ?? []).filter((item) => !currentIds.includes(item)), ...(previousState?.resolved_problem_units ?? []) ], stage2ProblemUnits_1.INVESTIGATION_MAX_RESOLVED_PROBLEM_UNITS) : capStrings(previousState?.resolved_problem_units ?? [], stage2ProblemUnits_1.INVESTIGATION_MAX_RESOLVED_PROBLEM_UNITS); const problem_unit_backlinks = active_problem_units .map((problemUnitId) => { const entity_backlinks = normalizeEntityBacklinks(currentBacklinksById.get(problemUnitId) ?? previousBacklinksById.get(problemUnitId) ?? []); if (entity_backlinks.length === 0) { return null; } return { problem_unit_id: problemUnitId, entity_backlinks }; }) .filter((item) => item !== null) .slice(0, stage2ProblemUnits_1.INVESTIGATION_MAX_PROBLEM_UNIT_BACKLINKS); const focus_problem_types = currentTypes.length > 0 ? currentTypes : capStrings((previousState?.focus_problem_types ?? []).map((item) => String(item)), stage2ProblemUnits_1.INVESTIGATION_MAX_FOCUS_PROBLEM_TYPES); const nextState = capProblemUnitState({ active_problem_units, resolved_problem_units, problem_unit_backlinks, focus_problem_types }); if (nextState.active_problem_units.length === 0 && nextState.resolved_problem_units.length === 0 && nextState.problem_unit_backlinks.length === 0 && nextState.focus_problem_types.length === 0) { return undefined; } return nextState; } function cloneInvestigationState(state) { if (!state) return null; const cloned = { ...state, focus: { ...state.focus, primary_accounts: [...state.focus.primary_accounts] }, evidence_refs: [...state.evidence_refs], open_uncertainties: [...state.open_uncertainties], followup_context: state.followup_context ? { ...state.followup_context, referenced_requirement_ids: [...state.followup_context.referenced_requirement_ids] } : null }; if (state.problem_unit_state) { cloned.problem_unit_state = capProblemUnitState({ active_problem_units: [...state.problem_unit_state.active_problem_units], resolved_problem_units: [...state.problem_unit_state.resolved_problem_units], problem_unit_backlinks: state.problem_unit_state.problem_unit_backlinks.map((item) => ({ problem_unit_id: item.problem_unit_id, entity_backlinks: [...item.entity_backlinks] })), focus_problem_types: [...state.problem_unit_state.focus_problem_types] }); } return cloned; } function createEmptyInvestigationState(sessionId, timestamp = new Date().toISOString()) { return { schema_version: stage1Contracts_1.INVESTIGATION_STATE_SCHEMA_VERSION, session_id: sessionId, status: "idle", turn_index: 0, updated_at: timestamp, question_id: null, focus: { domain: null, period: null, primary_accounts: [], active_query_subject: null }, narrowing_status: "unknown", evidence_refs: [], open_uncertainties: [], last_answer_mode: null, followup_context: null, query_mode_hint: "direct_answer" }; } function updateInvestigationState(input) { const previous = input.previous; const focusFromMessage = capStrings(detectAccounts(input.userMessage), stage1Contracts_1.INVESTIGATION_MAX_PRIMARY_ACCOUNTS); const requirementIds = capStrings(input.requirements.map((item) => item.requirement_id), stage1Contracts_1.INVESTIGATION_MAX_REQUIREMENT_LINKS); const mainRequirement = input.requirements[0]?.requirement_text ?? input.userMessage; const problemUnitState = updateProblemUnitState(previous, input.retrievalResults); return { schema_version: stage1Contracts_1.INVESTIGATION_STATE_SCHEMA_VERSION, session_id: previous.session_id, status: "active", turn_index: previous.turn_index + 1, updated_at: input.timestamp, question_id: input.questionId, focus: { domain: deriveDomain(input.routeSummary) ?? previous.focus.domain, period: detectPeriod(input.userMessage) ?? previous.focus.period, primary_accounts: capStrings([...focusFromMessage, ...previous.focus.primary_accounts], stage1Contracts_1.INVESTIGATION_MAX_PRIMARY_ACCOUNTS), active_query_subject: mainRequirement.slice(0, 180) }, narrowing_status: deriveNarrowingStatus(input.routeSummary, input.coverageReport), evidence_refs: capStrings([...collectEvidenceRefs(input.retrievalResults), ...previous.evidence_refs], stage1Contracts_1.INVESTIGATION_MAX_EVIDENCE_REFS), open_uncertainties: collectOpenUncertainties(input.coverageReport, input.retrievalResults), last_answer_mode: input.replyType, followup_context: { previous_question_id: previous.question_id, last_user_message: input.userMessage.slice(0, 240), referenced_requirement_ids: requirementIds }, query_mode_hint: deriveQueryModeHint(input.routeSummary), ...(problemUnitState ? { problem_unit_state: problemUnitState } : {}) }; }