import type { UndoManager } from "yjs"; /** * Helpers that bracket a sequence of AI-agent edits so they collapse into a * single undo step. * * Yjs UndoManager merges successive transactions that happen within the * `captureTimeout` window (500ms by default). `stopCapturing()` forces the * next transaction to start a fresh undo item, which we use as a *boundary * marker*: * * - `startAgentBatch()` is called once at the first tool call of a turn. * It separates the previous user edit from the agent batch. * - `endAgentBatch()` is called when the model finishes streaming. * It separates the agent batch from the user's next edits. * * Between the two markers, every Yjs-backed mutation issued by the agent * (replaceSelection, applyDiff, updateFrontmatter, ...) merges into one * undo item so a single `Cmd+Z` reverts the entire turn. * * The functions are no-ops when the manager is unavailable (early in the * editor lifecycle) or when the batch is already (in)active, which keeps * call sites trivial. */ export interface AgentBatchHandle { startAgentBatch(): void; endAgentBatch(): void; isActive(): boolean; } export function createAgentBatch( undoManager: UndoManager | null | undefined, ): AgentBatchHandle { let active = false; return { startAgentBatch() { if (undoManager && !active) { undoManager.stopCapturing(); active = true; } }, endAgentBatch() { if (undoManager && active) { undoManager.stopCapturing(); active = false; } }, isActive() { return active; }, }; }