/** * createDeltaBatcher — framework-free, append-only batching of the * `text-delta` / `thinking-delta` / `guide-delta` events. * * WHY THIS IS SHARED (and not a hook-private detail): every host that drives a * `ChatStreamReducer` from a raw transport needs the SAME batching, and a * copy-paste of it drifts. The React wrapper (`useChatStreamReducer`) and any * non-React mirror in a product app both consume this one implementation. * * Behaviour: * - `push(event, key)` queues delta events and returns true; anything else * returns false so the caller can flush + apply it synchronously (ordering: * completion state must always land on fully-applied deltas). * - CONSECUTIVE same-type deltas are COALESCED into one event (the reducer's * append semantics distribute over concatenation), so a 60-delta/sec turn * costs ONE `applyOne` per frame instead of 60. `text-delta` additionally * requires a matching `leading` flag before coalescing. * - A flush is scheduled on `requestAnimationFrame` when available, with a * timer fallback that is ALWAYS armed (rAF pauses in background tabs, and a * hidden chat panel must still keep its thread current). * - `key` is an opaque routing token handed back to `applyOne`. When it * changes, the pending batch is flushed against the PREVIOUS key first, so * deltas never land on the wrong dialog/side. */ import type { ChatStreamEvent, GuideDeltaEvent, TextDeltaEvent, ThinkingDeltaEvent } from '../../../chat-protocol/events'; export declare const DELTA_FLUSH_FALLBACK_MS = 50; export type DeltaEvent = TextDeltaEvent | ThinkingDeltaEvent | GuideDeltaEvent; export declare function isDeltaEvent(event: ChatStreamEvent): event is DeltaEvent; export interface CreateDeltaBatcherOptions { /** Apply one (possibly coalesced) delta against `key`'s reducer. */ applyOne: (event: DeltaEvent, key: K | undefined) => void; /** Called after a flush that applied at least one delta. */ onFlushed?: (appliedCount: number) => void; /** Timer fallback in ms (default `DELTA_FLUSH_FALLBACK_MS`). */ fallbackMs?: number; } export interface DeltaBatcher { /** * Queue `event` when it is a delta (returns true). Non-delta events are NOT * queued and return false — the caller flushes and applies them itself. */ push(event: ChatStreamEvent, key?: K): boolean; /** Synchronously apply the pending batch and cancel any scheduled flush. */ flush(): void; /** Flush and release timers — call on teardown so tail deltas aren't lost. */ dispose(): void; /** Queued (post-coalescing) delta count. Test/diagnostic surface. */ readonly pendingCount: number; } export declare function createDeltaBatcher({ applyOne, onFlushed, fallbackMs, }: CreateDeltaBatcherOptions): DeltaBatcher; //# sourceMappingURL=delta-batcher.d.ts.map