@@ -1518,7 +1518,7 @@ async function maybeExportSandboxFileToWorkspace(args: {
15181518 outputSandboxPath ?: string
15191519 overwriteFileId ?: string
15201520 outputMode ?: 'create' | 'overwrite'
1521- exportedFileContent ?: string
1521+ exportedFileContent ?: string | Buffer
15221522 result : unknown
15231523 stdout : string
15241524 executionTime : number
@@ -1599,9 +1599,9 @@ async function maybeExportSandboxFileToWorkspace(args: {
15991599 cost
16001600 )
16011601 }
1602- const fileBuffer = isBinary
1603- ? Buffer . from ( exportedFileContent , 'base64' )
1604- : Buffer . from ( exportedFileContent , 'utf-8' )
1602+ const fileBuffer = Buffer . isBuffer ( exportedFileContent )
1603+ ? exportedFileContent
1604+ : Buffer . from ( exportedFileContent , isBinary ? 'base64' : 'utf-8' )
16051605 const secretProvenance = await getOutputFileSecretProvenance ( fileBuffer , isBinary , routeContext , {
16061606 userId : authUserId ,
16071607 workspaceId : resolvedWorkspaceId ,
@@ -1691,8 +1691,8 @@ async function maybeExportSandboxFilesToWorkspace(args: {
16911691 workflowId ?: string
16921692 workspaceId ?: string
16931693 outputFiles : OutputFileDeclaration [ ]
1694- exportedFiles ?: Record < string , string >
1695- exportedFileContent ?: string
1694+ exportedFiles ?: Record < string , string | Buffer >
1695+ exportedFileContent ?: string | Buffer
16961696 result : unknown
16971697 stdout : string
16981698 executionTime : number
@@ -1780,7 +1780,9 @@ async function maybeExportSandboxFilesToWorkspace(args: {
17801780 args . cost
17811781 )
17821782 }
1783- const scanBuffer = isBinary ? Buffer . from ( content , 'base64' ) : Buffer . from ( content , 'utf-8' )
1783+ const scanBuffer = Buffer . isBuffer ( content )
1784+ ? content
1785+ : Buffer . from ( content , isBinary ? 'base64' : 'utf-8' )
17841786 const secretProvenance = await getOutputFileSecretProvenance (
17851787 scanBuffer ,
17861788 isBinary ,
@@ -1846,9 +1848,9 @@ async function maybeExportSandboxFilesToWorkspace(args: {
18461848 const writtenFiles = [ ]
18471849 try {
18481850 for ( const prepared of preparedFiles ) {
1849- const buffer = prepared . isBinary
1850- ? Buffer . from ( prepared . content , 'base64' )
1851- : Buffer . from ( prepared . content , 'utf-8' )
1851+ const buffer = Buffer . isBuffer ( prepared . content )
1852+ ? prepared . content
1853+ : Buffer . from ( prepared . content , prepared . isBinary ? 'base64' : 'utf-8' )
18521854 let previousSize : number | undefined
18531855 let unchanged = false
18541856 if ( prepared . target . mode === 'overwrite' ) {
@@ -2007,20 +2009,40 @@ async function discardUploadedExecutionFiles(files: readonly UserFile[]): Promis
20072009 }
20082010}
20092011
2010- async function collectExecutionOutputFiles ( args : {
2012+ async function collectSandboxOutputFiles ( args : {
20112013 routeContext : FunctionRouteExecutionContext
20122014 authUserId : string
20132015 workflowId ?: string
20142016 workspaceId ?: string
20152017 executionId ?: string
20162018 collectedFiles : SandboxCollectedFile [ ]
2019+ sandboxProfile ?: 'mothership'
2020+ result : unknown
20172021 stdout : string
20182022 executionTime : number
20192023 cost ?: FunctionExecutionCost
20202024} ) : Promise < { files : UserFile [ ] } | { response : NextResponse } > {
20212025 const { routeContext, collectedFiles } = args
20222026 if ( collectedFiles . length === 0 ) return { files : [ ] }
20232027
2028+ /** Chat exports use workspace ownership; only workflow exports need an execution scope. */
2029+ if ( args . sandboxProfile === 'mothership' ) {
2030+ const response = await maybeExportSandboxFilesToWorkspace ( {
2031+ ...args ,
2032+ outputFiles : collectedFiles . map ( ( file ) => ( {
2033+ path : `files/${ collectedFileName ( file . relativePath ) } ` ,
2034+ sandboxPath : file . path ,
2035+ mode : 'create' ,
2036+ mimeType : getMimeTypeFromExtension ( getFileExtension ( file . relativePath ) ) ,
2037+ } ) ) ,
2038+ exportedFiles : Object . fromEntries (
2039+ collectedFiles . map ( ( file ) => [ file . path , Buffer . from ( file . contentBase64 , 'base64' ) ] )
2040+ ) ,
2041+ } )
2042+ if ( ! response ) throw new Error ( 'Collected sandbox files require an export response' )
2043+ return { response }
2044+ }
2045+
20242046 const resolvedWorkspaceId =
20252047 args . workspaceId ||
20262048 ( args . workflowId ? ( await getWorkflowById ( args . workflowId ) ) ?. workspaceId : undefined )
@@ -2679,13 +2701,15 @@ export async function executeFunctionRequest(
26792701 }
26802702 }
26812703
2682- const shellOutputFiles = await collectExecutionOutputFiles ( {
2704+ const shellOutputFiles = await collectSandboxOutputFiles ( {
26832705 routeContext,
26842706 authUserId : auth . attributedUserId ,
26852707 workflowId,
26862708 workspaceId,
26872709 executionId,
26882710 collectedFiles : shellCollectedFiles ?? [ ] ,
2711+ sandboxProfile : auth . sandboxProfile ,
2712+ result : shellResult ,
26892713 stdout : shellStdout ,
26902714 executionTime,
26912715 cost : shellCost ,
@@ -2843,13 +2867,15 @@ export async function executeFunctionRequest(
28432867 }
28442868 }
28452869
2846- const jsOutputFiles = await collectExecutionOutputFiles ( {
2870+ const jsOutputFiles = await collectSandboxOutputFiles ( {
28472871 routeContext,
28482872 authUserId : auth . attributedUserId ,
28492873 workflowId,
28502874 workspaceId,
28512875 executionId,
28522876 collectedFiles : jsCollectedFiles ?? [ ] ,
2877+ sandboxProfile : auth . sandboxProfile ,
2878+ result : e2bResult ,
28532879 stdout,
28542880 executionTime,
28552881 cost : sandboxCost ,
@@ -2969,13 +2995,15 @@ export async function executeFunctionRequest(
29692995 }
29702996 }
29712997
2972- const pythonOutputFiles = await collectExecutionOutputFiles ( {
2998+ const pythonOutputFiles = await collectSandboxOutputFiles ( {
29732999 routeContext,
29743000 authUserId : auth . attributedUserId ,
29753001 workflowId,
29763002 workspaceId,
29773003 executionId,
29783004 collectedFiles : pythonCollectedFiles ?? [ ] ,
3005+ sandboxProfile : auth . sandboxProfile ,
3006+ result : e2bResult ,
29793007 stdout,
29803008 executionTime,
29813009 cost : sandboxCost ,
0 commit comments