/** Publish at most one event per block per window, so a chatty backend cannot outrun consumers. */ export declare const DEFAULT_FLUSH_MS = 120; /** …but never sit on more than this much text: a fast burst should reach the reader promptly. */ export declare const MAX_PENDING_CHARS = 400; export interface DeltaFlush { blockId: string; /** The chunks accumulated since the previous flush of this block — an increment, not a total. */ text: string; /** 0 for a block's first published event, +1 per event after that. Lets a consumer detect gaps. */ seq: number; } export interface DeltaCoalescerOptions { onFlush: (flush: DeltaFlush) => void; /** Window length; defaults to resolveFlushMs(process.env). */ flushMs?: number; /** Character cap that short-circuits the window; defaults to MAX_PENDING_CHARS. */ maxChars?: number; } export interface DeltaCoalescer { /** Accumulate one incremental chunk. Empty chunks are ignored. */ push(blockId: string, text: string): void; /** Publish what is pending for `blockId` (or for every block when omitted) right now. Callers * MUST do this before the block's complete message goes out, so the preview never trails the * authoritative text. */ flush(blockId?: string): void; /** Drop everything pending and cancel every timer — the coalescer stays inert afterwards. */ dispose(): void; } /** * Window length from the environment. Anything that is not a non-negative integer falls back to the * default rather than silently disabling batching. `0` is meaningful: publish on the next tick. */ export declare function resolveFlushMs(env: Record): number; export declare function createDeltaCoalescer(opts: DeltaCoalescerOptions): DeltaCoalescer; export interface SessionDeltaStream { /** Feed one incremental chunk from the adapter. */ onDelta(text: string, blockId: string): void; /** Publish what is pending — call this immediately before the block's complete message. */ flush(blockId?: string): void; /** End of turn: cancel timers, drop anything unpublished. */ dispose(): void; } /** * Bind the coalescer to one session's event stream — and decide whether that session may stream * at all. Returns null when it may not, which is the single place the "Web UI only" product rule * is enforced: * * - Slack, Feishu and the Ink TUI render complete messages through OutputStream; a partial block * there would mean edit-storms or duplicated text, so they get no stream and their code path is * byte-for-byte what it was. * - A session with no id has nothing to key events by. * - `CORTEX_STREAM_DELTAS=0` turns the whole feature off (the same switch that stops the CLI from * producing deltas in the first place). * * Callers therefore need no gate of their own: a null return means "no streaming callback". */ export declare function createSessionDeltaStream(args: { sessionId: string | null; channel: string; /** Injected for tests; defaults to the real EventBus publish. */ publish?: (p: { sessionId: string; channel: string; blockId: string; text: string; seq: number; }) => void; flushMs?: number; }): SessionDeltaStream | null;