@@ -13,13 +13,15 @@ const {
1313 mockGenerateId,
1414 mockIsExecutionCancelled,
1515 mockIsRedisCancellationEnabled,
16+ mockReadUserFileContent,
1617} = vi . hoisted ( ( ) => ( {
1718 mockBuildAuthHeaders : vi . fn ( ) ,
1819 mockBuildAPIUrl : vi . fn ( ) ,
1920 mockExtractAPIErrorMessage : vi . fn ( ) ,
2021 mockGenerateId : vi . fn ( ) ,
2122 mockIsExecutionCancelled : vi . fn ( ) ,
2223 mockIsRedisCancellationEnabled : vi . fn ( ) ,
24+ mockReadUserFileContent : vi . fn ( ) ,
2325} ) )
2426
2527vi . mock ( '@/executor/utils/http' , ( ) => ( {
@@ -37,6 +39,10 @@ vi.mock('@/lib/execution/cancellation', () => ({
3739 isRedisCancellationEnabled : mockIsRedisCancellationEnabled ,
3840} ) )
3941
42+ vi . mock ( '@/lib/execution/payloads/materialization.server' , ( ) => ( {
43+ readUserFileContent : mockReadUserFileContent ,
44+ } ) )
45+
4046function createAbortError ( ) : Error {
4147 const error = new Error ( 'The operation was aborted' )
4248 error . name = 'AbortError'
@@ -78,13 +84,14 @@ describe('MothershipBlockHandler', () => {
7884 mockIsExecutionCancelled . mockReset ( )
7985 mockIsRedisCancellationEnabled . mockReset ( )
8086 mockIsRedisCancellationEnabled . mockReturnValue ( false )
87+ mockReadUserFileContent . mockReset ( )
8188
8289 block = {
8390 id : 'mothership-block-1' ,
8491 metadata : { id : BlockType . MOTHERSHIP , name : 'Mothership' } ,
8592 position : { x : 0 , y : 0 } ,
8693 config : { tool : BlockType . MOTHERSHIP , params : { } } ,
87- inputs : { prompt : 'string' , conversationId : 'string' } ,
94+ inputs : { prompt : 'string' , conversationId : 'string' , files : 'file[]' } ,
8895 outputs : { } ,
8996 enabled : true ,
9097 } as SerializedBlock
@@ -212,6 +219,80 @@ describe('MothershipBlockHandler', () => {
212219 expect ( mockGenerateId ) . toHaveBeenCalledTimes ( 2 )
213220 } )
214221
222+ it ( 'embeds attached files for the mothership execute request' , async ( ) => {
223+ const fileContent = Buffer . from ( 'hello mothership' , 'utf8' ) . toString ( 'base64' )
224+ mockGenerateId . mockReturnValueOnce ( 'chat-uuid' )
225+ mockGenerateId . mockReturnValueOnce ( 'message-uuid' )
226+ mockGenerateId . mockReturnValueOnce ( 'request-uuid' )
227+ mockReadUserFileContent . mockResolvedValueOnce ( fileContent )
228+
229+ fetchMock . mockResolvedValue (
230+ new Response (
231+ JSON . stringify ( {
232+ content : 'analyzed' ,
233+ model : 'mothership' ,
234+ conversationId : 'chat-uuid' ,
235+ tokens : { } ,
236+ toolCalls : [ ] ,
237+ } ) ,
238+ {
239+ status : 200 ,
240+ headers : { 'Content-Type' : 'application/json' } ,
241+ }
242+ )
243+ )
244+
245+ const result = await handler . execute ( context , block , {
246+ prompt : 'Analyze this file' ,
247+ files : [
248+ {
249+ name : 'notes.txt' ,
250+ key : 'workspace/workspace-1/notes.txt' ,
251+ size : 16 ,
252+ type : 'text/plain' ,
253+ } ,
254+ ] ,
255+ } )
256+
257+ expect ( result ) . toMatchObject ( {
258+ content : 'analyzed' ,
259+ model : 'mothership' ,
260+ conversationId : 'chat-uuid' ,
261+ } )
262+ expect ( mockReadUserFileContent ) . toHaveBeenCalledWith (
263+ expect . objectContaining ( {
264+ id : expect . stringMatching ( / ^ f i l e - / ) ,
265+ key : 'workspace/workspace-1/notes.txt' ,
266+ name : 'notes.txt' ,
267+ url : '' ,
268+ size : 16 ,
269+ type : 'text/plain' ,
270+ } ) ,
271+ expect . objectContaining ( {
272+ encoding : 'base64' ,
273+ userId : 'user-1' ,
274+ workspaceId : 'workspace-1' ,
275+ workflowId : 'workflow-1' ,
276+ executionId : 'execution-1' ,
277+ requestId : 'request-uuid' ,
278+ } )
279+ )
280+
281+ const [ , options ] = fetchMock . mock . calls [ 0 ] as [ string , RequestInit ]
282+ const body = JSON . parse ( String ( options . body ) )
283+ expect ( body . fileAttachments ) . toEqual ( [
284+ {
285+ type : 'document' ,
286+ source : {
287+ type : 'base64' ,
288+ media_type : 'text/plain' ,
289+ data : fileContent ,
290+ } ,
291+ filename : 'notes.txt' ,
292+ } ,
293+ ] )
294+ } )
295+
215296 it ( 'propagates local aborts to the mothership request' , async ( ) => {
216297 const abortController = new AbortController ( )
217298 context . abortSignal = abortController . signal
0 commit comments