From cb172074479d071b780e649da4bbee2391d0d310 Mon Sep 17 00:00:00 2001 From: Waleed Date: Sat, 20 Jun 2026 18:28:26 -0700 Subject: [PATCH] fix(rich-md-editor): stop the editor flashing during an agent rewrite (#5160) * fix(rich-md-editor): stop the editor flashing during an agent rewrite Only reveal streamed chunks that extend what's already shown. A divergent chunk (an agent rewrite/edit, e.g. removing appended text) would collapse the document to the partial result and flash on every chunk; now the current content is held in place and the final result is applied once on settle. Fresh writes still reveal live. * fix(rich-markdown-editor): seed shown-body on settled mount and track local edits Seed lastSyncedBodyRef from a settled (non-streaming) mount and update it on local edits via onUpdate, so the streaming hold engages on the very first agent rewrite chunk (no collapse/flash) and the settle still applies the rewrite that removes a local edit. --- .../rich-markdown-editor.tsx | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/rich-markdown-editor.tsx b/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/rich-markdown-editor.tsx index 61d23c429b..afe14867be 100644 --- a/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/rich-markdown-editor.tsx +++ b/apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/rich-markdown-editor/rich-markdown-editor.tsx @@ -158,6 +158,14 @@ export function LoadedRichMarkdownEditor({ const [initialContent] = useState(() => streamingAtMountRef.current ? '' : parseMarkdownToDoc(splitFrontmatter(content).body) ) + /** + * The body currently shown in the editor: seeded from a settled mount, updated on local edits (via + * onUpdate) and on each streamed sync. The streaming tick reveals a chunk only when it extends this, + * so an agent rewrite holds the current content instead of collapsing to a partial result. + */ + const lastSyncedBodyRef = useRef( + streamingAtMountRef.current ? null : splitFrontmatter(content).body + ) const onChangeRef = useRef(onChange) onChangeRef.current = onChange const onSaveShortcutRef = useRef(onSaveShortcut) @@ -263,13 +271,12 @@ export function LoadedRichMarkdownEditor({ }, onUpdate: ({ editor }) => { const md = postProcessSerializedMarkdown(editor.getMarkdown()) + lastSyncedBodyRef.current = md onChangeRef.current(applyFrontmatter(settledRef.current?.frontmatter ?? '', md)) }, }) editorInstanceRef.current = editor - const lastSyncedBodyRef = useRef(null) - const wasStreamingRef = useRef(streamingAtMountRef.current) const pendingStreamBodyRef = useRef(null) @@ -291,6 +298,12 @@ export function LoadedRichMarkdownEditor({ streamRafRef.current = null return } + const shownBody = lastSyncedBodyRef.current + const extendsShown = shownBody === null || pending.startsWith(shownBody) + if (!extendsShown) { + streamRafRef.current = null + return + } if ( pending.length > STREAM_REPARSE_THROTTLE_THRESHOLD && performance.now() - lastStreamParseAtRef.current < STREAM_REPARSE_THROTTLE_MS @@ -303,7 +316,7 @@ export function LoadedRichMarkdownEditor({ lastStreamParseAtRef.current = performance.now() const el = containerRef.current const pinnedToBottom = el ? el.scrollHeight - el.scrollTop - el.clientHeight < 80 : false - editor.setEditable(false) + if (editor.isEditable) editor.setEditable(false) editor.commands.setContent(parseMarkdownToDoc(pending), { contentType: 'json', emitUpdate: false,