import { parseTurnQuestion, persistedOfferFromTurn, type TurnQuestion } from "./rectification-agentic/v9/turn-question.ts"; export type SnapshotTurnMessage = { role: "assistant" | "user"; turnId?: string; text: string; renderKey: string; question?: TurnQuestion; candidateOffer?: { resultId: string }; }; export function mergeTurnQuestions( current: T[], turns: readonly unknown[], ): T[] { const byId = new Map(); for (const item of turns) { if (!item || typeof item !== "object") continue; const turn = item as { id?: unknown; question?: unknown; offer_result_id?: unknown }; if (typeof turn.id !== "string") continue; byId.set(turn.id, { question: parseTurnQuestion(turn.question), offerResultId: typeof turn.offer_result_id === "string" ? turn.offer_result_id : null, }); } return current.map((message) => { if (!message.turnId || !byId.has(message.turnId)) return message; const next = byId.get(message.turnId); const question = next?.question ?? undefined; return { ...message, question: question ?? undefined, candidateOffer: persistedOfferFromTurn( next?.offerResultId, message.candidateOffer, true, ), }; }); } export function appendUnseenAssistantTurns( current: T[], extras: readonly T[], ): T[] { const known = new Set(current.flatMap((message) => message.turnId ? [message.turnId] : [])); const incoming = extras.filter((message) => ( message.role === "assistant" && message.turnId && !known.has(message.turnId) )); return incoming.length ? [...current, ...incoming] : current; } export function applySnapshotTurnsToMessages( current: T[], turns: readonly unknown[], extrasFromTurns: (turns: readonly unknown[]) => T[], ): T[] { return mergeTurnQuestions( appendUnseenAssistantTurns(current, extrasFromTurns(turns)), turns, ); }