1+ import { isUserFile } from '@/lib/core/utils/user-file'
12import { groupIterationBlocks } from '@/lib/logs/execution/trace-spans/iteration-grouping'
23import { createSpanFromLog } from '@/lib/logs/execution/trace-spans/span-factory'
34import type { TraceSpan } from '@/lib/logs/types'
@@ -37,7 +38,7 @@ function setFilteredValue(output: Record<string, unknown>, key: string, value: u
3738 * returned as-is, so a block log shares structure with the block's compacted
3839 * state output instead of holding a second copy for the rest of the run. A
3940 * copy starts only at the first changed child; non-plain prototypes (Date,
40- * class instances, null-prototype objects) are always rebuilt.
41+ * class instances, null-prototype objects) and file objects are always rebuilt.
4142 */
4243export function filterHiddenOutputKeys ( value : unknown ) : unknown {
4344 if ( value === null || value === undefined ) {
@@ -63,8 +64,10 @@ export function filterHiddenOutputKeys(value: unknown): unknown {
6364
6465 if ( typeof value === 'object' ) {
6566 const entries = Object . entries ( value as Record < string , unknown > )
67+ // File objects are always copied: file hydration later updates `size` in
68+ // place on the shared state object, and a log keeps the value it completed with.
6669 let filtered : Record < string , unknown > | undefined =
67- Object . getPrototypeOf ( value ) === Object . prototype ? undefined : { }
70+ Object . getPrototypeOf ( value ) === Object . prototype && ! isUserFile ( value ) ? undefined : { }
6871 for ( let index = 0 ; index < entries . length ; index ++ ) {
6972 const [ key , val ] = entries [ index ]
7073 const hidden = HIDDEN_OUTPUT_KEYS . has ( key )
0 commit comments