@@ -109,4 +109,80 @@ describe('FileToolProcessor', () => {
109109
110110 expect ( mockUploadExecutionFile ) . not . toHaveBeenCalled ( )
111111 } )
112+
113+ it . each ( [ Buffer . alloc ( 0 ) , '' , { type : 'Buffer' , data : [ ] } ] ) (
114+ 'stores valid zero-byte inline files as UserFile outputs: %j' ,
115+ async ( data ) => {
116+ const storedFile = {
117+ id : 'empty-file' ,
118+ key : 'workspace/workspace-1/empty-file' ,
119+ name : 'empty.txt' ,
120+ size : 0 ,
121+ type : 'text/plain' ,
122+ url : '/api/files/serve?key=workspace%2Fworkspace-1%2Fempty-file' ,
123+ } satisfies UserFile
124+ mockUploadExecutionFile . mockResolvedValue ( storedFile )
125+
126+ const result = await FileToolProcessor . processToolOutputs (
127+ {
128+ file : {
129+ name : 'empty.txt' ,
130+ mimeType : 'text/plain' ,
131+ data,
132+ url : 'https://example.com/file' ,
133+ } ,
134+ } ,
135+ toolConfig ,
136+ executionContext
137+ )
138+
139+ expect ( result . file ) . toEqual ( storedFile )
140+ expect ( mockUploadExecutionFile ) . toHaveBeenCalledWith (
141+ expect . objectContaining ( { workspaceId : 'workspace-1' , executionId : 'execution-1' } ) ,
142+ Buffer . alloc ( 0 ) ,
143+ 'empty.txt' ,
144+ 'text/plain' ,
145+ 'user-1'
146+ )
147+ expect ( mockDownloadFileFromUrl ) . not . toHaveBeenCalled ( )
148+ }
149+ )
150+
151+ it ( 'preserves empty file entries in file-array outputs' , async ( ) => {
152+ const result = await FileToolProcessor . processToolOutputs (
153+ { file : [ { name : 'empty.txt' , mimeType : 'text/plain' , data : '' } ] } ,
154+ { ...toolConfig , outputs : { file : { type : 'file[]' } } } ,
155+ executionContext
156+ )
157+
158+ expect ( result . file ) . toHaveLength ( 1 )
159+ expect ( mockUploadExecutionFile . mock . calls [ 0 ] ?. [ 1 ] ) . toEqual ( Buffer . alloc ( 0 ) )
160+ } )
161+
162+ it ( 'stores a successful zero-byte URL download' , async ( ) => {
163+ mockDownloadFileFromUrl . mockResolvedValue ( Buffer . alloc ( 0 ) )
164+
165+ await FileToolProcessor . processToolOutputs (
166+ { file : { name : 'empty.txt' , mimeType : 'text/plain' , url : 'https://example.com/empty' } } ,
167+ toolConfig ,
168+ executionContext
169+ )
170+
171+ expect ( mockUploadExecutionFile . mock . calls [ 0 ] ?. [ 1 ] ) . toEqual ( Buffer . alloc ( 0 ) )
172+ } )
173+
174+ it . each ( [ undefined , null , '!!!' , { type : 'Buffer' , data : 'invalid' } ] ) (
175+ 'does not turn missing or malformed data into an empty file: %j' ,
176+ async ( data ) => {
177+ await expect (
178+ FileToolProcessor . processToolOutputs (
179+ { file : { name : 'invalid.txt' , mimeType : 'text/plain' , data } } ,
180+ toolConfig ,
181+ executionContext
182+ )
183+ ) . rejects . toThrow ( "Failed to process file output 'file'" )
184+
185+ expect ( mockUploadExecutionFile ) . not . toHaveBeenCalled ( )
186+ }
187+ )
112188} )
0 commit comments