export type DraftStreamLoop = { update: (text: string) => void; flush: () => Promise; stop: () => void; resetPending: () => void; resetThrottleWindow: () => void; waitForInFlight: () => Promise; }; export function createDraftStreamLoop(params: { throttleMs: number; isStopped: () => boolean; sendOrEditStreamMessage: (text: string) => Promise; }): DraftStreamLoop { let lastSentAt = 0; let pendingText = ""; let inFlightPromise: Promise | undefined; let timer: ReturnType | undefined; const flush = async () => { if (timer) { clearTimeout(timer); timer = undefined; } while (!params.isStopped()) { if (inFlightPromise) { await inFlightPromise; continue; } const text = pendingText; if (!text.trim()) { pendingText = ""; return; } pendingText = ""; const current = params.sendOrEditStreamMessage(text).finally(() => { if (inFlightPromise === current) { inFlightPromise = undefined; } }); inFlightPromise = current; const sent = await current; if (sent === false) { pendingText = text; return; } lastSentAt = Date.now(); if (!pendingText) { return; } } }; const schedule = () => { if (timer) { return; } const delay = Math.max(0, params.throttleMs - (Date.now() - lastSentAt)); timer = setTimeout(() => { void flush(); }, delay); }; return { update: (text: string) => { if (params.isStopped()) { return; } pendingText = text; if (inFlightPromise) { schedule(); return; } if (!timer && Date.now() - lastSentAt >= params.throttleMs) { void flush(); return; } schedule(); }, flush, stop: () => { pendingText = ""; if (timer) { clearTimeout(timer); timer = undefined; } }, resetPending: () => { pendingText = ""; }, resetThrottleWindow: () => { lastSentAt = 0; if (timer) { clearTimeout(timer); timer = undefined; } }, waitForInFlight: async () => { if (inFlightPromise) { await inFlightPromise; } }, }; }