@@ -103,20 +103,22 @@ export const ResourceContent = memo(function ResourceContent({
103103 const isUpdateStream = streamOperation === 'update'
104104
105105 const { data : allFiles = [ ] } = useWorkspaceFiles ( workspaceId )
106- const activeFileRecord = useMemo ( ( ) => {
107- if ( ! isPatchStream || resource . type !== 'file' ) return undefined
108- return allFiles . find ( ( f ) => f . id === resource . id )
109- } , [ isPatchStream , resource , allFiles ] )
106+ const previewFileId =
107+ streamingFile ?. fileId ?? ( resource . type === 'file' ? resource . id : undefined )
108+ const previewFileRecord = useMemo ( ( ) => {
109+ if ( ! previewFileId ) return undefined
110+ return allFiles . find ( ( f ) => f . id === previewFileId )
111+ } , [ previewFileId , allFiles ] )
110112
111113 const isSourceMime =
112- activeFileRecord ?. type === 'text/x-pptxgenjs' ||
113- activeFileRecord ?. type === 'text/x-docxjs' ||
114- activeFileRecord ?. type === 'text/x-pdflibjs'
114+ previewFileRecord ?. type === 'text/x-pptxgenjs' ||
115+ previewFileRecord ?. type === 'text/x-docxjs' ||
116+ previewFileRecord ?. type === 'text/x-pdflibjs'
115117
116118 const { data : fetchedFileContent } = useWorkspaceFileContent (
117119 workspaceId ,
118- activeFileRecord ?. id ?? '' ,
119- activeFileRecord ?. key ?? '' ,
120+ previewFileRecord ?. id ?? '' ,
121+ previewFileRecord ?. key ?? '' ,
120122 isSourceMime
121123 )
122124
@@ -125,15 +127,28 @@ export const ResourceContent = memo(function ResourceContent({
125127 if ( ! streamOperation ) return undefined
126128
127129 if ( isPatchStream ) {
128- if ( ! fetchedFileContent ) return undefined
130+ if ( fetchedFileContent === undefined ) return undefined
131+ if ( ! shouldApplyPatchPreview ( streamingFile ) ) return undefined
129132 return extractPatchPreview ( streamingFile , fetchedFileContent )
130133 }
131134
132135 const extracted = streamingFile . content
133- if ( extracted . length === 0 ) return undefined
134136
135137 if ( isUpdateStream ) return extracted
136- if ( isWriteStream ) return extracted
138+
139+ if ( streamOperation === 'append' ) {
140+ if ( streamingFile . targetKind === 'file_id' ) {
141+ if ( fetchedFileContent === undefined ) return undefined
142+ return buildAppendPreview ( fetchedFileContent , extracted )
143+ }
144+ return extracted . length > 0 ? extracted : undefined
145+ }
146+
147+ if ( streamOperation === 'create' ) {
148+ return extracted . length > 0 ? extracted : undefined
149+ }
150+
151+ if ( isWriteStream ) return extracted . length > 0 ? extracted : undefined
137152
138153 return undefined
139154 } , [
@@ -165,16 +180,11 @@ export const ResourceContent = memo(function ResourceContent({
165180 }
166181 } , [ workspaceId , streamFileName ] )
167182
168- // workspace_file preview events now carry whole -file snapshots, not deltas.
169- // Treat every live preview as replace so the viewer shows the latest snapshot .
183+ // ResourceContent now reconstructs full -file preview text per operation,
184+ // so the viewer can always treat streaming content as a whole-file replace .
170185 const streamingFileMode : 'append' | 'replace' = 'replace'
171186
172- // For existing file resources (not streaming-file), only pass streaming
173- // content for patch operations where the preview splices new content into
174- // the displayed file. Update operations re-stream the entire file from
175- // scratch which causes visual duplication of already-visible content.
176- const embeddedStreamingContent =
177- resource . id !== 'streaming-file' && isUpdateStream ? undefined : streamingExtractedContent
187+ const embeddedStreamingContent = streamingExtractedContent
178188
179189 if ( streamingFile && resource . id === 'streaming-file' ) {
180190 return (
@@ -700,3 +710,27 @@ function extractPatchPreview(
700710
701711 return undefined
702712}
713+
714+ function shouldApplyPatchPreview ( streamingFile : {
715+ content : string
716+ edit ?: Record < string , unknown >
717+ } ) : boolean {
718+ const edit = streamingFile . edit ?? { }
719+ const strategy = typeof edit . strategy === 'string' ? edit . strategy : undefined
720+ const mode = typeof edit . mode === 'string' ? edit . mode : undefined
721+
722+ // delete_between is delete-only and can be previewed from intent metadata alone.
723+ if ( strategy === 'anchored' && mode === 'delete_between' ) {
724+ return true
725+ }
726+
727+ // For all other patch modes, keep the visible file unchanged until
728+ // edit_content actually streams content into the target location.
729+ return streamingFile . content . length > 0
730+ }
731+
732+ function buildAppendPreview ( existingContent : string , incomingContent : string ) : string {
733+ if ( incomingContent . length === 0 ) return existingContent
734+ if ( existingContent . length === 0 ) return incomingContent
735+ return `${ existingContent } \n${ incomingContent } `
736+ }
0 commit comments