AIAI EngineerFeb 6, 2025· 1:48:16

[Full Workshop] How to add secure code interpreting in your AI app: Vasek Mlejnsky

Vasek Mlejnsky, CEO of E2B, demonstrates how to add secure AI code execution to any app using E2B’s Code Interpreter SDK alongside Anthropic's Sonnet 3.5 and Vercel’s AI SDK. The workshop builds an open-source version of Claude’s artifacts UI, running Python code in isolated Firecracker VMs that start in ~900ms and support custom environments via Dockerfiles. Vasek explains how E2B’s Jupyter-server-based sandbox returns stdout, stderr, runtime errors, and rich outputs like PNG charts, which are streamed to the front end using Vercel’s stream data. He covers security architecture—full root access in a VM that self-destructs on escape—and plans for AWS/GCP self-hosting and snapshot-based agent branching. The episode also addresses customizing sandboxes with private packages, mounting cloud storage (S3, GCS), and interpreting table previews as HTML or images.

  1. 0:00Setup
  2. 17:38Basic Chat
  3. 27:26Tool Definition
  4. 33:30Sandbox Setup
  5. 44:20Code Execution
  6. 1:01:42Display Results
  7. 1:09:21Stream Data
  8. 1:22:48Preview Render
  9. 1:29:08Q&A

Powered by PodHood

Transcript

Setup0:00

Vasek Mlejnsky0:15

Hi everyone.

Guest0:16

Oops.

Vasek Mlejnsky0:17

Uh, thanks for coming—thanks for coming to my, uh, to my workshop. My name is Vasek, and today I will show you, and you can code along, how to add AI Code Interpreting into your AI app, or into your app.

So,

what we will be building will be very similar to Claude's new AI artifacts app that they—or Anthropic's AI artifacts app that they just released about 2 days ago. So if you are not familiar with it, the way it looks like is that you have a chat on the left, and on theright you have this preview.

And what this preview does is that Claude can write code. In Claude's case, it's supported just for HTML, JS, and CSS code, if I'm not mistaken. And then it actually renders and runs the coderight next to the chat.

We'll build something very similar with a few caveats, and first is that

we will be able to run AI-generated Python code, not just HTML, CSS, and JavaScript. I will also show you at the end how to run other

runtimes and other languages. And we will be using E2B, which is a company that I co-founded, for secure code interpreting, and you can code along while we are building it. So here's a quick demo of what we are going to build.

On the left, we'll be chatting with Sonnet 3.5, and every time it generates code, it's actually implemented through function calling. We will run that code in a secure sandbox that can run pretty much anything that a Linux machine or Ubuntu machine can run, and you can spawn many, many of these sandboxes for secure code interpreting.

The workshop is made for code along, but of course you can just watch. But if you are interested in actually following me, you can go to our repository and clone the cookbook, and then check out the workshop start.

And you also will need two API keys. One of them is E2B API key, which—oh, sorry—which you can get on our documentation. So E2B: https://e2b.dev/docs. Then you go to API key, you sign up, and we give you your API key.

And also, you will need an Anthropic's API key. In case you don't have that, or you don't want to get it, I created one for this workshop. And so if you go to—and you are free to—well, I kind of trust you that you will not misuse it.

If you go to dev.sh/etub-workshop, you can get the API key for free. I will delete it after the workshop.

So I know everyone had a lunch, so you're probably kind of tired. I will try to keep it sort of short, so it most likely will not take 2 hours. We will get to the result much faster.

So I will give you like a few quick minute, a few seconds, or tens of seconds to set up everything.

But just to get a better idea, how many of you want to follow along? Okay, cool.

Guest4:33

What's download speed?

Vasek Mlejnsky4:34

Sorry?

Guest4:36

It's again, the repository's quite big. I'm at 42%.

Vasek Mlejnsky4:41

Oh, shoot. That's probably because we have images there that you can generate with the—oh, sorry, I didn't realize that.

Guest4:50

Just so you know.

Vasek Mlejnsky4:51

Yeah, yeah. That's a good point. By the way, if anyone has any questions, just like feel free to ask during the workshop. If anything isn't clear, I will repeat the question and try to give you an answer.

Okay, yes.

Guest5:21

Is the Code Interpreter running on our machines or not?

Vasek Mlejnsky5:24

Mm-hmm. So the question is, is Code Interpreter running on your machine or somewhere else? The Code Interpreter isn't running on your machine. It's using

a tool called E2B, which I'm a co-founder of, and we're basically building a runtime for, open-source runtime for AI agents that you can, and very soon will be, to self-host on AWS, GCP, Azure, and other big cloud providers.

I can go a little bit more into detail of what's the whole problem and challenge with Code Interpreting around security. I was thinking that maybe first we implement the app so you can kind of get an idea of how it works, and then during Q&A or after that I can get into the security and what are the challenges if you want to build this in-house.

Cool. So how's the repo cloning look like?

Guest6:31

It's slow.

Vasek Mlejnsky6:32

Slow? Oh, shoot.

Okay.

Guest6:37

Do you want to just go to the GitHub and download it there?

Vasek Mlejnsky6:41

Sorry?

Guest6:41

Do you want to just go to GitHub and download it there?

Vasek Mlejnsky6:43

Sorry?

Guest6:43

Do you want to just go to the GitHub and download it there?

Vasek Mlejnsky6:45

Oh, yeah. That's a good point. You know what, let me—I probably can create very quickly just the repo without other examples.

And I will just put the example that we are interested in there,

which should be much smaller.

Guest7:13

Can you just tell me if you can just—excuse me—if there are links to your slides? Sorry if I missed that.

Vasek Mlejnsky7:18

I don't have slides.

Guest7:20

Is there a link to what you're showing us?

Vasek Mlejnsky7:22

Yeah. So if you go

to https://github.com/etub/etub/etub/cookbook, you go to Examples,

and there's this Anthropic—it's called Power Artifacts—and we will be building like an open-source version of Anthropic's new artifacts UI that has Sora Code Interpreting in it.

Okay.

Oh, cool. Okay. Let me just quickly set up the new repository.

Okay, this one should be much smaller. If you go to this URL, I will show it on a big screen.

If you go to this URL, which is my personal GitHub, and go to /workshop-repo, you should be able to clone it

much faster.

Actually, sorry.

Guest9:34

That link is in the Slack now, in general.

Vasek Mlejnsky9:37

Thank you. Perfect.

Okay, you should be able to clone it now. I didn't have—I have only README there. Now all the files are there. And, oh, I don't have branches there. I just realized. Actually, this should be good. It should be good.

Yeah, yeah, good. Perfect. So sorry for the confusion. Let me

do it again properly.

Okay. So if you want to clone, if you want to code along, please go to this GitHub repository and clone it. This should be much faster. Is it faster?

Guest10:46

Yeah.

Vasek Mlejnsky10:46

Perfect. And do you already have it cloned?

Guest10:49

Yes.

Vasek Mlejnsky10:49

Perfect. Okay, so now we can start.

After you clone it, just install dependencies, and you will also need those API keys. So if you create a file .env.local, which will need E2B API key and Anthropic API key. You can get E2B API key on

this website. So if you go to etub.dev, click Get Started, and go to API key. If you quickly sign up, you can get your API key. If you just want to follow along,

yeah, if you just want to log, you don't need an API key. And you will also need Anthropic's API key. And in case you don't want to spend your money on that, I created

an Anthropic API key just for this workshop. So if you go to this link, it should open a 1Password

share model or share website, and you can get your Anthropic API key there, and I will cancel it after the workshop.

All good?

Guest12:20

Yes.

Vasek Mlejnsky12:21

Perfect. So once you have your API key set up, install dependencies, and then just run npm run dev.

And you should see what I'm seeing here. The app should start on port 3000. So what we are doing just now is we started a Next.js app, which is like a starting point, and we will now follow. You can now follow and code along, and I will show you how to add the Code Interpreting there.

So if you open the app,

it, oops,

it just shows an input, which is like this is a scaffold of the app where you can ask code something. So let's say we want to generate a random chart, and actually now it won't work because we need to implement everything.

So I just hit an Enter, but I should be getting, or you should see in your terminal, 405.

So now that we have everything set up, in case I'm too fast, just like scream at me, and I will slow down or just wait for you. Now we have everything set up. I want to just quickly show around the code, around the repository, and what we will be doing.

So there are two important parts of this project. First is what we are going to use is Vercel's AI SDK, and this in the JavaScript world is essentially like an easy and nice way how you can connect to different models and stream them to your front end from your back end.

So it's already installed when you ran npm install. In case you want to check out the docs after the workshop or during, go to this link. And the second thing that we will be using is the Code Interpreter SDK.

So that's something that we built at E2B. And essentially what it does, it's open-source, and what it does is that you can create your own custom Code Interpreter and

that you can predefine the whole environment. That Code Interpreter runs in a sandbox, which is like a small VM. When you are using our cloud, it runs on our cloud. Soon we will be able to self-deploy it. And specifically for this SDK, inside that sandbox is a Jupyter server running to which you can just send Python, JavaScript, R code, and Java code that we have in beta.

And you get back standard output, error output, but you also get back charts. So the reason we are using a Jupyter server there is because that's what we notice has been one of the most frequent use cases from our users and our customers.

And generally, at least during the time of GPT-4 and for Turbo, the code that you usually got from the LLM

was for Python, like data science Jupyter notebook. And it's really great for visualization, which is like a big use case for what we are seeing with users.

Just a quick note, this whole Code Interpreter SDK is built on like a general sandbox, which is a small VM. We start those VMs pretty quickly, around a few hundred milliseconds. Every time you create an instance of Code Interpreter, we actually create that sandbox.

So this is kind of like a wrapper around our sandbox SDK that's also open-source, which is here. And so if you want to build something pretty, pretty custom, you can do that. So Code Interpreter is like one specific use case of how you can use this sandbox.

You can look at this sandbox as a general Ubuntu machine that's made with security in mind for running like AI-generated code.

So as you noticed, when we were running this app, when I wrote something, I just hit an Enter and nothing happened. So first we need to implement an endpoint

to call the VM. Sorry, to call the LLM. And for that, we are using Vercel's service function, and there's a predefined file called road.ts. And here is commented out a function that will handle our POST requests that we need to implement.

And here we will be using the Vercel's AI SDK.

So now we finally start coding, and now we will do just like a simple

Basic Chat17:38

Vasek Mlejnsky17:47

implementation of messaging with Claude. First,

we need to parse those messages coming from the request, and

then we actually

use the AI SDK, Vercel's AI SDK, and from that we will be using the stream text method.

And so the model we are using is Anthropic,

which is the Sonnet one, and we want to parse the messages. Oh, yeah, there's an evade I was missing. And

we also want to include a system prompt. And so I already predefined a prompt in a file. It should be in a lib directory. There is a prompt file. And so the prompt is really simple. It's a simple prompt that tells the LLM Sonnet that it's a skilled Python developer that can do a bunch of visualizations.

So let's import that variable

prompt.

Okay. And

add it here.

And now that should be pretty much it for the basic implementation. Now we just need to return stream from our POST endpoint. So result.toAIStreamResponse. All these are methods on the Vercel's AI SDK. So

if you are more curious, you can just jump into it there and into the documentation. But if we go back to our application, sorry, now we should see that if I type hello, first our message is there and we get a response from Claude.

Am I too fast or are you following?

Guest20:10

Yeah.

Vasek Mlejnsky20:10

Too fast?

Guest20:11

Define messages.

Vasek Mlejnsky20:12

Sorry?

Guest20:12

Are you to define messages?

Vasek Mlejnsky20:14

Yeah. So the messages,

so this is just the back end part. Oh, yeah. And it's coming in the request.

Guest20:28

What's the prompt?

Vasek Mlejnsky20:32

The prompt is, sorry, I will show it here,

in a file.prompt.ts and it basically just says that it's a skilled Python developer that's capable of running like a visualization on data science code. It would work for different use cases as well. Now I just wanted to show something where we at the end get a chart that you can render on the front end.

One more thing that I wanted to mention is that in case you are not follow, you are like lost over what just happened, in the original repository, in the examples repo, there are branches called workshop one, workshop two, workshop three, workshop four and five.

And those are like the stages that we are implementing here. So in case you are wondering what is happening, it should be pretty much the same. And if you just want to get through the final point, you can check out the workshop-final and you should get everything there.

Guest21:58

I'm just trying to see if it's created.

Vasek Mlejnsky22:00

Sorry?

Guest22:01

The prompt is, is it created in the directory?

Vasek Mlejnsky22:05

That file should already be there. It's in a lib directory. Lib-prompt, yeah.

So while we have the main back end code on the left, I just also wanted to show you how it looks like on the front end really quickly. It's a basic Next.js app, Next.js 13 app. So there is a layout file

that just defines a basic layout of the whole app, but there's one important or main important file which is called page, which is our main page. And there we are using one hook from the Vercel's AI SDK, which is called use chat.

And this is how we are streaming the messages from the server and sending the messages to the server. So the use chat here, it's already implemented there. You don't need to write it. It's hitting the endpoint /api/chat, which is what we implemented on the left.

And it takes care of all the streaming and sending the messages on the back end. And we just then pass the messages to our chat component, which does those chat bubbles.

Guest23:39

So how did you get your, what kind of code did you generate? Should I just ask you to generate Python?

Vasek Mlejnsky23:45

Now the goal was just to get a communication with Claude, with Sonnet, and

later we will implement Python.

Guest23:55

Right.

Vasek Mlejnsky23:55

Yeah. We will add a tool for running Python. So we will do it through function calling or tool usage.

Guest24:04

If anyone needs it, there's a channel now for the workshop. So code can get thrown in there.

Vasek Mlejnsky24:09

Thank you.

Okay. So how many of you

have managed to get to this stage? Just a few people. Okay. How many of you are still working? Okay.

Guest24:34

What's the name of the Slack channel? Workshop secure code in your AI. It's listed in general there.

Vasek Mlejnsky24:41

So the name of the Slack channel is Workshop Secure Code in your AI,right? Yeah.

Yeah.

Guest24:55

Sign the branch again. Sorry?

Vasek Mlejnsky24:57

Sorry?

Guest24:58

Sign the branch.

Vasek Mlejnsky24:59

So name of the branch, so the repository we are working with is

this repository. This is my personal repository. I just created it quickly now because the original cookbook repository wasn't working. Is that the question?

Guest25:18

No, the original one.

Vasek Mlejnsky25:19

Oh, the original one. Yeah. So that is workshop-start.

Guest25:28

And the original repository was just start and then it quoted.

Vasek Mlejnsky25:32

Yeah. That's the original repo I wanted to use, but it's too big and it took too much time for everyone to download it. But if you want to check out the final code for this first step, you can go to original repository and there workshop-1.

And that should be the implementation of this step pretty much.

Okay. Can I get to the next step?

Guest26:12

Yeah.

Vasek Mlejnsky26:14

Cool. So now we just are able to chat with Sonnet. There really isn't any code execution going on. And the way we get through the code execution is in this case through tool usage. So you could do it in different ways.

The easiest out of the box is create a tool called something like run Python in our case for this specific use case. And then inside the tool, we will actually implement the secure code execution inside the sandbox. You could have other tools like run JavaScript or run bash command, create a file inside the sandbox, or you could do it in a completely different way.

So we have seen users just ditching tool usage because it was pain for the streaming and they didn't like how we managed the whole tools. And they just asked the model to define, sorry, to generate everything in Markdown and they just parse it themselves.

So it's really depending on your use case and what you are looking for, but like for this demo, tool is the easiest one. So

Tool Definition27:26

Vasek Mlejnsky27:26

now we are getting to part two. So if you want to eventually get the final code, we can go to workshop-2. And first thing that we want to define is a new tool on

our back end inside the Vercel's AI SDK. So for that, we have a helpful helper method called tool, and

we want to create run Python. We will call our tool run Python. You can name it in whatever way you want.

And there we will use the tool method from Vercel's AI SDK

and just describe what it should do to the LLM. So in JavaScript world, usually you would be using something like Zod for that that describes the schema of the tool. In Python, you might be using, you might know Instructor or something like that.

So first we will provide like a simple description

that just runs Python code. And then we want to define the parameters for the tool. And we really have one main parameter, which is code. That's the code we want to run.

And for that, we will be, now we will be using, oh, sorry, I should have used Zod here.

So Zod object, we are basically describing the schema to the LLM and forcing it to always generate or return this type of structure. So, sorry.

First we defined code, which should be string, and we can also pass description, which is the code to run. This is the main thing we want to pass. And just for the, oh, I'm missing a colon here. Just for the better UI that we can then build, we will also pass two more parameters or ask LLM to pass, give us two more parameters.

First is title, which is like a short title

that describes the code. And we just wanted to show it on the front end. And then a description,

which is pretty much similar, but

just a little bit longer of description of what the code does. So just by doing this, we are telling, or Vercel's AI SDK is doing it for us. It's telling the LLM that it has a tool called run Python that it can call, but we are not calling it just yet.

Is everything clear so far?

Or let me ask differently. Is something not clear?

Guest30:54

There's a typo, short.

Vasek Mlejnsky30:56

Oh, thank you.

So.

Guest31:06

What's the version of the AI SDK doing here?

Vasek Mlejnsky31:09

Sorry?

Guest31:10

The SDK you're talking about.

Vasek Mlejnsky31:11

The AI SDK? Yeah. So that's an SDK that we are using. It's literally called just AI SDK. It's from Vercel. You can learn more about it if you go to sdk.vercel.ai/docs.

And it's basically

like JavaScript, a very easy way to stream output from LLMs and to LLMs in JavaScript world, and especially if you are building like Next.js apps.

So inside that tool that we are using, run Python, we need to implement one more function, which is called execute. It will be async function.

And this function is then automatically called when the LLM decides to call our run Python tool. And the parameters that we just defined here will get passed to the execute function. So what we will get here, mainly what we really care about here, or really the only thing we care about, is the code.

And currently, like nothing is going to really happen, but inside this body of this function, we will be calling the Code Interpreter SDK that I showed you previously and the Code Interpreter Sandbox where we execute the code and we get the results from that.

Okay. So there's one more new concept that we are going to introduce, which is the concept of the sandbox. We have a predefined file called sandbox. It's in the lib directory. So if you go to lib, you go to sandbox.

I will open it here on theright side. You will see there's an import that we are using, which is Code Interpreter.

Sandbox Setup33:30

Vasek Mlejnsky33:40

And we are importing Code Interpreter from the Code Interpreter SDK, which is this SDK I was talking about a few minutes ago. So what this SDK does is that it will run AI-generated code, in this case Python code, in a secure environment.

And it will be actually running inside the sandbox, which is a small VM. It will run on our cloud. Soon we will be able to run it on your own cloud.

We have two methods here that we need to implement. First is that we need to acquire the sandbox, or we need to create the sandbox. And once we have a sandbox, we then can run the Python code inside the sandbox, inside the Code Interpreter sandbox.

And there we have predefined methods on the Code Interpreter sandbox for that.

Guest34:38

You said this works in the cloud.

Vasek Mlejnsky34:41

In the cloud. In the cloud. Yeah. So

once we implement this, I can go into more details about the security and problems with actually running it on anything else but the Linux machine. But yeah, if you have any questions, like feel free to ask after that.

Yeah, go ahead.

Guest35:03

Is there a Sonnet-related question? I know you've mixed JS a little bit, but you've got the run Python on line eight on the left-hand side there. It looks like it's a key, but it also refers to the function.

Vasek Mlejnsky35:21

This one?

Guest35:22

Yeah.

Vasek Mlejnsky35:23

Oh, it's just a, oh, I see the confusion. Sorry. We are not referring to the, you mean this function? Referring to this function?

Guest35:32

Yeah. Is that a key or a function?

Vasek Mlejnsky35:34

It's a key. So on the line 27 where my cursor is, it's a key of the object. And sorry, I didn't realize that. We will be very soon calling this run Python function that we are importing from the file on theright.

Guest35:49

Yeah. That naming is just coincidence.

Vasek Mlejnsky35:53

Yeah, yeah, yeah, yeah. That's a good question. I didn't realize that. Thanks.

Yeah. So the question was, it was confusion about the naming. So here we have a key called, or field called run Python. And there we also are importing a function called run Python on the line 15 here. And it's just a, it's not, the line 27 is not actually referring to the function from the line 15.

It's just a coincidence of the naming.

Guest36:28

Is that function being used on the 15?

Vasek Mlejnsky36:31

The one on the line 15? We are about to use it very, very soon. So we are just going to implement it. So the definition of the function, or

the function is defined inside the file sandbox that we have on theright. It's inside the lib directory. And this is where we will be using the Code Interpreter SDK.

So first we need to, first we need to actually get the sandbox, the Code Interpreter sandbox. And for that, we can do it very, very quickly, simply. And that would be that we create a new sandbox instance. So we imported Code Interpreter here on line 7 from the Code Interpreter SDK.

And we can just call this. And we get, this actually starts the full, like small VM inside our cloud that you can control through the SDK. It takes about currently 800, 900 milliseconds to start it. And you can do it many, many times advanced.

So usually what we see is that every user inside your app, every user session would be a separate sandbox.

And once we have the sandbox, oh, sorry. Oops. Actually, we need to, sorry, we need to call Code Interpreter dot create. I didn't realize. And we need to await that. That was Python syntax what I just wrote.

And this creates what I just said. There's one problem with this is that now every time if I would call this

endpoint, post endpoint on my back end, and I would just call run Python function and then create a new sandbox, there will be no concept of context. So it would create a new sandbox every time, and you would be just running the new code in a completely new sandbox every time you don't have any reference to past code snippets that are generated by the LLM.

So for that, you can actually have a sandbox running and reconnect to it a little bit later by calling reconnect. So what we will change a little bit in our create or connect function is that we first check if the sandbox exists for a given user ID, which would be something like a user session that you would implement once you have authentication.

And if it has, we will connect to the sandbox. If it doesn't exist, if it exists, we connect to the sandbox. If it doesn't exist, we create a new sandbox.

So

we can first list all the sandboxes,

which is Code Interpreter dot list. You need to add the await there. And once we have all the sandboxes, we can check if the sandbox has attached user ID onto its metadata. So what you can do when you are creating a new sandbox is that you can add metadata to the sandbox.

And if the sandbox with our user ID inside its metadata exists, we want to connect to the sandbox. So we keep our old session and have the whole context there.

So first we want to find the sandbox if it exists.

And so we call find on the all sandboxes, which is a list of information of all our sandboxes that are running. And

then we call metadata. And on that metadata, which is like optional object or dictionary, it should have user ID key that should be equal to the parameter that we will be passing to this create or connect method.

And

we want to await this whole code, this code. Oops.

Okay.

So is everything clear?

And once we have our sandbox info,

we check it actually exists.

And if it doesn't exist, that's the moment we want to create a new sandbox. So we will be actually here

returning a new sandbox. And as I said, you can add metadata to the sandbox. So we will just use this metadata to make a note that, sorry, to make a note that

this sandbox belongs to this user. In our case, it will be just one user, but in your application, you would have many, many users.

So that's a case when the sandbox didn't exist and we need to create one. And this line will create a new sandbox in the cloud. And in case we have a sandbox with a user ID inside its metadata, we want to just connect to that sandbox.

And for that, we have a function called reconnect on the Code Interpreter object. And there you just pass the sandbox ID and that we can get from the sandbox we found on the line 11.

Sandbox info dot sandbox ID. And let's just return it. So what this does is that at first we, okay, I don't know, we check all our running sandboxes because we probably have a separate sandbox for every user or every user session most likely.

And then once we have all the running sandboxes, we check the metadata of each sandbox and check if a user ID, if the sandbox has the same user ID for which we are calling this create or connect method.

If it doesn't, if such sandbox doesn't exist, we will just create a new one. We attach user ID to this sandbox metadata

and return this whole promise and object from the promise. If it actually exists, this sandbox for this user, we will just reconnect to the sandbox.

Any question or is everything clear?

Code Execution44:20

Vasek Mlejnsky44:20

Cool. So there's one, actually now we finally can get to implementing theright run Python method. So once we have our code, this await does, oh, sorry, this await doesn't need to be here. Once we have our code for creating or connecting to our existing sandbox, we can just call it.

So create or connect to the sandbox

inside this run Python function. We pass our user ID. And once we have this sandbox, we can finally run the code. So let's also add console log to make sure that we know what kind of code we are running.

And I mentioned that inside the sandbox or the Code Interpreter sandbox in this case, we have a Jupyter server running. And we give you programmatic access to the Jupyter server. So you can call notebook on a sandbox instance and call exec cell.

And by default, this method will execute Python code. It can be AI generated, human written, predefined, whatever you want.

And we just pass our code there. And

we get results, result from it. And just need to await that and return the result.

Oh, probably we want to log it as well.

Guest46:12

If you run multiple codes,

is it like a Jupyter notebook where you have the cells and the session is consistent?

Vasek Mlejnsky46:24

Yes, yes. So it's really just like a legit Jupyter notebook. We actually have a PR where you can connect to that notebook that's hosted inside the sandbox. It's probably at the moment the easiest way how to implement like a consistence, sorry, implement persistence when you have multiple different code snippets where one code snippet can reference a variable from a different code snippet or function.

And so during the single user session, you just want to keep usually what we have seen, a single context, but it really depends always on your specific use case.

Is anyone struggling with the run Python implementation? Yeah.

Guest47:20

So this is the exec cell will capture standard out, but you also mentioned standard error from these.

Vasek Mlejnsky47:27

Yeah.

Guest47:28

How do you capture the other?

Vasek Mlejnsky47:29

The result, so the question is, if exec cell returns, it seems like it just returns standard output,right? Yeah. So what it returns is our custom object or execution. And there you have access to standard output, error output, and in runtime errors that are nicely parsed with

traceback that you can feed back into LLM to fix itself. And also any rich output like PDFs, charts, PNG, JPEG files. And we'll be just sending this to the front end where we can use it and present it to the user.

So this run Python function, it's the function that we

are importing on the left in our endpoint when we are calling the LLM where we implemented the stream text. And we can finally, we can finally call the run Python function inside our execute method. So

there's really nothing too special about it. One thing that we need to do though is that we need to use that user ID. So we also need to get user IDs from somewhere.

We will be just sending this from the front end. So let's say in a real application, you would probably have like an authenticated session with the user ID. In this case, we will just send it from the front end.

I will add it in a minute. And that user ID, we pass through that run Python method. And

once we have results, we want to return the results from the execute function. So when we call return here and we are returning an object, that's what we'll get sent to the front end with LLM's answer. So that's like the result of the function call or tool call.

Okay. So

just to make sure I don't forget anything.

Yeah. So is that part clear how we are importing the run Python function to our post, the road file, and just we want to call that with the AI generated code and then get the results to the front end.

So now we are getting to a more interesting part. And once we implement this, we'll have like actual running it inside our app and we can try the app again.

And we get to what you just asked. And we can get different types of output from the result. So first is we want standard output. And the result object from our exec cell, we are just returning it here.

It contains logs. So we get standard output. It contains

error logs. So oops, error output. And it also contains two more things. Any runtime error. So that's an error that you would get when AI probably generated

wrong code or code that doesn't work. We can catch that. And we will return that in an error field, which is nicely structured that you can use to fix itself. And the last part is that

we get something called, I have a little bit unfortunate naming here called cell results essentially. So let's name it cell results. And those are like evaluated, it's an evaluated notebook cell that's inside a sandbox.

And those can be those charts, images, PDF files, HTML, JSON. It can be just like text. So it's usually the last line of a Jupyter cell in a Jupyter notebook. And also anytime you call like a display data, like you want to display a chart or anything like that, that will be in a cell results, which is like an array of results.

And based on the type of a result, you can then parse it.

And all these four objects, we just return it

from the execute function, which will get us to, which will get it to the front end.

Any questions for this part? Mm-hmm. Go ahead.

Guest52:48

Can you speak to like Python version packages and that stuff?

Vasek Mlejnsky52:52

Yeah. So the question is about Python version packages and everything probably inside the sandbox and the environment.

For the Code Interpreter SDK, so I mentioned that the Code Interpreter SDK is wrapping a sandbox. And that sandbox can be completely predefined by you. In our case, when we created a Code Interpreter SDK, we installed a bunch of packages that you would probably usually use in like a data science use case or AI data analysis use case like NumPy, Pandas, Seaborn is installed there.

And so that's like something that gets you going out of the box. And there's also Python 3.10 installed in the environment. You can also create a completely custom sandbox if you want to, if you just give us a Docker file.

And inside the Docker file can install whatever package you want. But you will be just using a little bit lower level API that we have. It's not scary. It's just like you need to set up everything yourself. So usually you start with the Code Interpreter SDK.

And then once you find out, hey, I don't need these packages or I need different, you can install whatever you want. Question there?

Guest54:09

I was curious on your choice of the Jupyter framework for the Code Interpreter. You mentioned that because the appliance is already used, like you get any other rational goals of intent that might be a little more secure or something.

Vasek Mlejnsky54:26

So here we really went just with an optimized, so sorry. The question was how we went about choosing the Jupyter framework inside the sandbox. If there's any more to it than what I mentioned. So the main decision was how we should set up the sandbox that out of the box, it's working for you when you plug it to an LLM and you don't get much like errors.

Because that's what users come to us, especially if they are a little bit less experienced with LLMs and they are wondering why it's not working. So we were really optimizing on how most likely will AI generated Python code or code will look like.

And the answer is it's going to be Python code and it's going to be like a Jupyter notebook code with pre-installed packages. It's essentially like what your GPT-4 would expect. And that means what their Code Interpreter tool would have installed.

Yeah.

Guest55:30

Are you able to expose the Jupyter environment as a notebook to use that?

Vasek Mlejnsky55:35

So the question is if you are able to expose the Jupyter notebook inside a sandbox. Yes, you can. It's, so, oh, sorry.

So that's not like documented anywhere, but you actually can set up exactly this because we have few customers

that wants to implement something like this. The answer is just text us on Discord or just send us an email and we will give you a guide. We have like few experimental PRs like that. For example, we have a sandbox with full working graphical interface where you can start apps like game.

So everything is Linux, but you can pretty much start anything you want there. A lot of people has been using it for, or have been using it for evals when you want the LLM control something more graphical. Or if you want to build something that's more like a tandem human in the loop, you can do that as well.

So just to sum it up, we implemented the POST request and the execute, sorry, the run Python tool. That's finally now we should be able to run the code on the front end. So one last thing we need to do is that we need to go to our page component, page.tsx.

And

there we need to create this like a dummy user ID.

This would be, because we are now passing it on the front end. In your real app, you actually had, you would actually had a user ID. And

in the use chat hook that's coming from the AI SDK, we just pass the user ID to body.

And let's add a console log here to the messages so we can check if everything is working correctly.

And if I go back to my app, open

my Chrome DevTools.

And I see something like simple, like print hello world.

I can see I'm getting the messages. There's a new UI that wasn't there before. And if I check the messages, the reason there's so many messages is because like it's constantly streaming them. So it's updating the messages object.

And so one message, first message is my prompt, print hello world. And actually, can I zoom this in? Yeah. First message is print hello world. And the second message is from the assistant, which has the answer. And there's also something interesting called tool invocations, which is an array of all the tool invocations that the assistant or LLM decided to do.

And one of them, the only one there is the run Python that we defined. It has two important fields, arcs and result. So arcs, that's what we described when we were defining that

tool, that run Python tool. So this is the code. That's what we ask it. And the result, that's what we returned from that execute method inside that POST function or execute function. And there we have cell results, like an empty array because really, so cell results doesn't capture any standard output.

It just evaluates the Python code. And there was nothing to evaluate. Like as a side effect of print is just nothing. No error output, but in the standard output we have hello world. And that's what we wanted. So now if we ask it to actually for actually something more complex, like calculate by using Monte Carlo method and visualize it, it will take a little bit time.

Now it's writing the code, which unfortunately isn't streamed at the moment because the tool streaming isn't implemented there in the AI SDK. But if we check it out, we have a tool invocation here, which is our run Python.

It has the whole code here.

It's taking 1,000 or 10,000, 100,000 iterations. So it will actually most likely take a little bit of time to finish this. And if we, yeah, and we got two new messages because we got a result from the run Python code.

And if we check it again, there's a tool invocations. We have result. And yeah, we have standard output. But the interesting part is that in cell results, we now have

one of the results, which has PNG and text fields. So PNG is a base 64 image from the cell. And that's the visualization of the Monte Carlo simulation. And the text is just like a human-friendly description of the chart.

Now what we will work now on in the next step is displaying this on the front end, on theright side in the artifact.

Guest1:01:42

It's still processing.

Display Results1:01:42

Vasek Mlejnsky1:01:44

No, no. It's here. It's already finished. If you check out the cell results,

you see the PNG. And that's what we asked it. The reason we don't see it anywhere here inside the app is because we haven't implemented the front end yet. That's what we are going to do now. But we already have results from the Code Interpreter sandbox in our messages variable.

Guest1:02:09

Where did you get the messages from?

Vasek Mlejnsky1:02:11

So the question is, where did I get the messages from? This is code on the front end. If you go to page.tsx,

this line, the use chat line is returning all the messages from the LLM, including tool calls.

Guest1:02:32

Thank you.

Vasek Mlejnsky1:02:33

Yeah.

Any questions? So I would say we are pretty near the end now. We need to just display it. And for that, we need to parse the tool invocation from the message, latest message with it. We need to get the latest message with the tool invocation.

So I will, like for the sake of simplicity, I will just do something a little bit naive here. And that is, I will just care about the latest message we get from the LLM. And from the latest message, I will just parse the tool invocations that was there.

So first we get the latest message. Oops.

That has tool invocation. And this is a little bit annoying, but first we need to reverse the array

in JavaScript. And then we search in this for message that had tool invocation field. And that field wasn't empty. So that array wasn't empty. So

the length will be bigger than zero. So this can or might or might not exist. This latest message with tool invocation, it will not exist

in the first few seconds once we give an LLM a prompt to actually do something and generate code.

And now we just want to extract that tool invocation field from our, oops,

from our message with tool invocation. And it, again, it can or might or might not exist. So both latest message with tool invocation can be message or undefined. And the tool invocation can be a tool invocation or undefined.

So we, so far we just added these two

function calls or two calls.

And we are working with messages that were sent from the back end. And that's the part that we implemented up until now.

The reason we are doing this is that we will be sending the tool invocation to the component that I will add in a sec. And that component will be showing the chart that, and any output from the running the AI generated code.

Any questions?

Okay. Once we have a tool invocation,

we want to display it. And for that, I have a pre-made component called sideview

that exists in components and sideview file. And we, so we can just import it from there.

And we want to render itright next to the

chat

component. So, and this sideview takes the tool invocation. That's why we did what we did with those messages here. So I imported the sideview here. It's a component that already exists inside a project. And I'm now rendering the sideview next to the chat component that we already have there.

And if you check out the app,

when you, when we ask,

when we ask the Claude to print something, oops. Yeah, it's working now.

It should, oops, it's not displaying.

It should display the sideview, but for some reason it's not showing now. And that might be I forgot something to implement inside the sideview. Do you need more time to add the sideview to this file or I can go to sideview?

Okay.

Oh yeah. The sideview has

one thing that I forgot and that it also expects a field called data. And what that field does is that we want something that shows us that the tool, that the LLM is using the tool and we are waiting for it.

And we want to know about it on the front end. So we want to send some additional data with the LLM's response from our server, from our endpoint.

And unless the way sideview is implemented, unless there is no this kind of data, there can be any data, it will return null. So the idea is just simple. We want to show some kind of loader. And

I want to show you how you can know about what is happening with the tool execution more than just like waiting for a new message. So for that, if we go back to road file, and there we have imported an object called stream data.

And stream data is a helper object from the AI SDK. And that will help us to stream any arbitrary data back to the front end alongside our messages from the LLM. So we will just, here

Stream Data1:09:21

Vasek Mlejnsky1:09:41

below parsing the request, we will just create a data object called stream data. Oops.

And it's a stream. And we can append objects into that stream. So what we want to do is when we are calling execute

or when the tool gets called, we want to first say, hey, the

tool run Python is running.

Oops. It's not update. It's append.

And once we get what we need, we also want to update the stream with

basically the same. Just the status will be

complete. And that's what I arbitrarily picked. You can pick whatever you really want. And it's just like how the sideview component is implemented

inside our front end. But the idea is that like now you can use the stream data to send arbitrary data from the back end through the front end and stream it, which is an important part. What is just missing now that we need to include that stream data object to our response from our API endpoint.

And for that, we need to just do two things. First, we need to close that stream data stream because it's a stream. So it's currently open when we created it. And we also need to change the return here to include the data that we, the stream, additional stream.

So we kind of need to create two streams that we are combine them in a single stream and send it to the front end. And

for that, what we are going to do is first the result from the LLM call, which is this result from the stream text, can be converted to a stream. So result to

AI stream. And there we can do one thing and that's we can pass it a callback called on final, which is once everything is done, we want to close our data stream.

Okay.

So this, what this does is that it converts our result from the LLM that we are using with, we get from stream text to a stream. And once LLM is finished with generating all the responses, that's what this callback on file tells us.

We want to close our data stream that we created a few moments ago. And the last missing part is just now we want to, we want to return both the stream and the data. So for that, there's an object called streaming text response from the AI SDK.

It's already imported.

And if we call it, you can pass it three, should pass it three parameters. First is the stream, which is the response from the AI. Second is the initial data. We don't want any. And the last is any

arbitrary data that you want to send along the stream. Okay.

Any questions?

Guest1:14:18

What checkpoint are you on?

Vasek Mlejnsky1:14:20

This should be stage

workshop dash four.

Guest1:14:37

Can you go back to page.tsx?

Vasek Mlejnsky1:14:39

Mm-hmm.

So actually on the page.tsx, what we need to do is we need to get the data object from the use chat hook. So that's what we are going to add now.

Guest1:15:16

So we already modified everything on the sideview.

Vasek Mlejnsky1:15:19

Oh, sorry?

Guest1:15:20

Sideview. Sideview file, we already modified everything.

Vasek Mlejnsky1:15:24

The question is if we have modified sideview component. We haven't yet. We just are rendering sideview component here. But it needs additional data about the information if the code is still running, the AI generated code. And that's what we are adding now.

And once we add that, it should display.

So if you, one last part for this data stream is that we need to extract the data from the, that we are sending from the back end and get it on the front end. So use chat, again, from the AI SDK is pretty handy here because we can just add, it just returns another field called data, which is exactly what we are sending.

We can even print it. And

all we need to do is once we get the data variable, we just pass it as a prop to our sideview.

And that should be it.

And now if you go to the app again and ask it anything that would result in generating code,

it's a little bit, Sonnet is a little bit slow. Yeah. And now we have the sideview rendered. And it's currently just showing code. But what we will add as the last part of this workshop is the preview. And there we will be rendering any charts returned from the Code Interpreter and any standard output and error output.

Guest1:17:36

Can you repeat the question? What's the special about Anthropic's Claude here?

Vasek Mlejnsky1:17:42

The question is what's special about Anthropic's Claude model here?

You could use any model you want. It's just the new Sonnet model is really good with code generation. And so it usually is capable of one shot, same like relatively, I would say like advanced examples. Not like full projects, but it can give you interesting results.

Yeah. Question?

Guest1:18:22

You mentioned that all of your runtimes are Linux at the moment. And I wondered, I think you said that there were some security reasons that that was the case. And I wonder if you could expand on that a little bit.

Vasek Mlejnsky1:18:33

Yeah. The question is that all the sandbox runtimes are Linux. And what are the reasons for that? And probably if those are security reasons. So yeah, that's correct. All those runtimes are Linux. And so there are two parts of that question and the answer.

So the sandbox is a regular VM. It's not a container. And that VM is running on our server, on a host machine. And so both host machine and the sandbox operating system is Linux. The reason for that is that we are using something called Firecracker, which is an open source VM from AWS.

And they are using it for running AWS Lambdas. So it's really battle tested with running untrusted code. And Firecracker is very specific in a way that it requires Linux with specific kernel for security reasons. And inside the Firecracker, inside the VM, you really can't run anything else at the moment than Linux.

Yeah. Sorry. Go ahead.

Guest1:19:55

So you mentioned that the dependencies are all taking as default in the sandbox,right? So how hard would it be, I'm just curious, to read the imports and customize the sandbox?

Vasek Mlejnsky1:20:07

It's basically just your custom Docker file. So the question is how hard would it be to customize the sandbox,right?

Guest1:20:14

Yes.

Vasek Mlejnsky1:20:16

With install custom dependencies. You would just give us your Docker file. And inside the Docker file, you would have something like pip install, whatever you want. Or you can have even npm. If you want to build a little bit more communication on top, you can, we have users running, sorry, Fortran.

So you can really run anything you want. Depends on how much customizability you want. I can show it after the call. But if you go, sorry, after the workshop, if you go to our documentation, e2b.dev/docs, we have a guide there for customization,

specifically for the Code Interpreter SDK.

Yeah.

Guest1:21:11

You mentioned Firecracker. And there was also a document there on top of it. So is it like a two-level?

Vasek Mlejnsky1:21:19

Yeah. So the question is that if we are using just Firecracker or Firecracker and containers together, I think like the confusion comes from the Docker file I mentioned. Yeah. So we are using just Firecracker. The containers and the Docker file,

we are using that only for like a simple way to define your Firecracker environment, essentially. So what we do on the background, once you give us your Docker file to customize the sandbox, is we start it as a container, extract the file system, and then convert it to Firecracker VM.

And then when you start your sandbox, you are essentially starting your custom container programmatically. Yeah. Question there?

Guest1:22:11

What's like the starting time in your custom container?

Vasek Mlejnsky1:22:15

What's the static, what's the timing?

Guest1:22:17

Yeah. Like if you start the sandbox.

Vasek Mlejnsky1:22:20

Oh, yeah. So how much time does it take to start the custom sandbox? It takes the same time as pre-made sandbox. So at the moment, it should be around 900 milliseconds every time you call that sandbox.create that I wrote there in SDK.

And soon it should be around 400 milliseconds.

Preview Render1:22:48

Vasek Mlejnsky1:22:48

Okay. Now we are getting to the last part of this workshop. And that's in case you want to just check out, get checked out to the last part. It's workflow dash five. And we will go into the sideview.

And what we want to do, we want to implement this preview.

So that's essentially the result of the code execution that we get from the LLM.

Let me close a few files first. So we really care about the sideview component, the only thing we care for now. And if we open the sideview component,

it's like scaffold and predefined. The thing that's missing there is that we have

an artifact view component that also already exists. That's currently commented out. So that we need to uncomment inside the sideview. And inside, let me turn that on left, put it on left. And inside the

artifact view that's on theright now,

if you go to artifact view function, which is the component, we have a bunch of to-dos. So let's focus now on one main to-do and item, and that's render image. And so let's just optimize now for the use case where we want the LLM to render a chart or any image, any image that we want.

And we want to display that image here. So what artifact view gets through props propagation is the result of our code execution. That's the result here. That's what we send from the back end. That's this file.

And we want to access the cell results because cell results has this object has all the PNG files, JPEG files, HTML, PDF, everything around that.

So

you can see that we are already doing the parsing here. When we are extracting the cell results, standard output, error output, and runtime error from our result object. And if there are any cell results,

we just expect there will be PNG. In a real app, you probably would need to check that a little bit more thoroughly. And if we have a PNG file, we will just render image. And that's basically it. So I will just add a little bit more styling here.

We will use Next.js image component. And because the image is PNG image is in base64, that's exactly what we are going to use here.

And the width and the size will be like 600, 400. It's really arbitrary for now. And

we just want to put this image in a diff container.

So it's centered.

And make it a little bit nicer with padding.

And render our logs there. The logs output is something that's already prepared here in this file.

So once we add this, when we should see an image inside our app, if we ask for something like that Monte Carlo, or just like generate or create a random chart, like 3D chart.

And here it is. So this came straight from the sandbox, from the

Jupyter server running inside the sandbox. The next step would be that we won't be able to cover in this workshop. But next step would be how to make these charts interactive. Because now it's just an image generated from the sandbox.

One of the ways to do that, I'm going to go back to code. One of the ways to do that would be use the sandbox not for generating images, but to operate on top of charts, sorry, on top of CSV files and your data set.

So what you can do is that you can upload files to the sandbox. You can connect a cloud storage to a sandbox that you already have a bunch of files. And you can just let AI know, the LLM know about how these files look like, like CSV files, what columns are there.

And just ask it questions about this data set. And with usual like Sonnet 3.5 is very capable of this already. It will start generating

code that's capable of extracting data from your CSV file, send the data, run that code inside the sandbox on top of your CSV file, send it to a front end, and on the front end generate or display this data with something like ChartJS, Bodley, any library you want.

Yeah. The question?

Q&A1:29:08

Guest1:29:09

How table previews are used?

Vasek Mlejnsky1:29:11

Sorry, can you repeat that?

Guest1:29:12

Does Code Interpreter have table previews? Can it display table previews?

Vasek Mlejnsky1:29:16

If we can display table previews? So yeah. The question is if we can display table previews, yes. So anything you could display besides like interactive widgets inside a Jupyter notebook, you will get in the result object or cell results object.

And it can be data frames, for example.

Guest1:29:39

Is that an image? Or is it an interactive widget?

Vasek Mlejnsky1:29:44

The question really is, it depends. Sorry. So the question is if the table preview is an image or something, or just like a description of the table. The answer is it depends. It depends on what you tell the LLM to do.

So if you ask the LLM to use theright libraries that when our evaluated return, for example, HTML, you will get HTML on front end and you can just display it. So yeah. It depends on how the AI generated code looks like and what kind of libraries you are using and dependencies you are using inside the Code Interpreter.

Yeah. Question here.

Guest1:30:28

Can you say anything more about security architecture? I mean, you've given us this. I guess it's really simple, but it's just executing in a sandbox. But do you want to say more about it?

Vasek Mlejnsky1:30:38

Yeah. So the question is if I can go a little bit deeper into the security of the sandbox.

So Firecracker really does very heavy lifting here. And the way it works and our infrastructure works is that you start a sandbox. We have a small VM prepared for you. And that VM is the Firecracker VM. And the VM is designed in a way that when you try to get outside of the VM, it just restarts.

So we are actually giving you full root access. You can run any comment you want. And when you, unless there's like a network hole somewhere where you could just connect to a third-party service, when you try to something like exit or system restore or anything like that, the machine will just restart and will just start a new sandbox for you.

On top of that, that Firecracker is wrapped inside a jailer, which removes the ability to run certain syscalls, which usually you shouldn't really care about. Everything just works as you would expect. And the way Firecracker works for the high-level security is that it's using Linux's kernels, KVM, for virtualization.

So there's a little bit more overhead instead of containers because it's a full VM. It's not just a process. And so every user session is a separate VM that is isolated and

really doesn't know about other VMs or sandboxes inside the network. So it's out-of-the-books multi-tenant environment if you look at the sandbox as a single tenant.

Guest1:32:38

Say that again?

Vasek Mlejnsky1:32:39

It's a multi-tenant environment if you look at the sandbox as one of the tenants.

Yeah. Question.

Guest1:32:47

Can you save the data? The code as well as the result, do you log that in your system?

Vasek Mlejnsky1:32:54

The question is if we save any data that you sent to the Code Interpreter sandbox or to the sandbox. The answer is no. So at the moment, when you start a sandbox and you kill the sandbox at some point, or it just closes by itself, everything is destroyed.

And what we log is only that you did certain operations. So you, for example, created a file, but we don't save content of the file. We just want to know about what is happening inside the VM. And what you can do for the persistence is you can connect your cloud storage to the VM and save the data there.

Yeah.

Guest1:33:45

These VMs, is it getting randomly created on the cloud? How do you pre-configure these VMs? Can you repeat a little longer? You mentioned about the Docker files that you can pre-configure a Python version and respective packages. How do you start on that?

Vasek Mlejnsky1:34:05

Yeah. So the question is that I mentioned Docker files for customizing the sandboxes and the VMs.

Yeah. So

actually, I can show it to you here. If you go to etube.dev/docs, what you can do there is we have a way to customize the Code Interpreter. And the way we do it

is through a Docker file. And it's a regular Docker file where you can use most of Dockerfile things and keywords. It just needs to be Ubuntu-based. And basically, what the Dockerfile is good for is that you can define the file system of the VM, the environment of the VM.

And that can be like you can install any packages. You can define any environment variables, save any files, or pre-save any files. So we have users save like a scaffolded Next.js app that just the LLM can send render generated components.

And then the Next.js app is just running inside the VM. And so the Dockerfile really is just like a means of letting us know how you want the environment to look like. And then we just convert that Dockerfile, actually that container, to a VM.

Does that answer the question? Yeah. Here's a question.

Guest1:35:40

The conversion from Dockerfile to Firecracker VM, is that a standard process? Or is it, I mean, how standard a process is that? Like you're layering one file system from Ubuntu to Firecracker VM. Is it because they both are the same Linux-based kernels that they just convert?

Vasek Mlejnsky1:36:01

It's the question is

how does it look like that conversion from a container to a sandbox,right? Like that file system. It's actually much simpler than it sounds. So what we really do is just, you know, like you know how you have different types of file systems in your computer.

I don't think many people touch it nowadays. But back in the days, if you are booting your machine, you can pick how your file system would look like. That's what essentially we do. So we run the container. And on our infrastructure, there's literally a shell command that copies the whole file system to an outside file outside from the container.

And we just convert that file to the correct format. And that format is supported as a root file system for the Firecracker. So it really is just a bunch of files together that we extract from the container. And it's very similar to how the container gets created.

So if you want, you could theoretically, you know, images have this bunch of tar files and layers. You could extract those layers from the image. And you wouldn't probably even, most likely, didn't need to run the container. And you could just take the image and convert it to the file system for the VM.

Guest1:37:31

Is that conversion code as part of your codebase?

Vasek Mlejnsky1:37:35

Yeah. It's in the codebase. So we are fully open source.

We have a bunch of repositories here. There's a repository called infra, which is a little bit less known.

One disclosure is it's not that now very friendly to get it running on your own. That's the next thing we are working on. And here, if you take a look into especially scripts, you will find a script for conversion of the Dockerfile to the sandbox, the VM file system.

There was one question first.

Guest1:38:14

Yeah. How do you end up registering your own custom modules inside the sandbox?

Vasek Mlejnsky1:38:19

Yeah. So the question is how do we end up registering custom modules inside the sandbox? Very similarly like what I talked about it a few times. When you are creating, you can create a Dockerfile that describes how the sandbox will look like.

We convert the Dockerfile to your custom sandbox. And then we start a sandbox. You can start a sandbox using the SDKs.

Because the Dockerfile creation happens with your Docker instance, we are not doing it on our cloud. We can use private packages or private images or whatever you really want. Yes. Question.

Guest1:39:03

So I was looking at this report earlier. And it says, I think, at the bottom that GCP is kind of the only platform that's supported currently. Do you have plans to support others in the future?

Vasek Mlejnsky1:39:13

The question is if we have plans for supporting other clouds than GCP. Yeah. Strong yes. So AWS is actually where we are even migrating with our cloud version. We want to support AWS as the first thing. Then we will have a proper tutorial for GCP.

And the next one is supporting any Linux machine, so custom on-prem clouds.

Guest1:39:41

Just as a follow-up, so is your business model eventually, so instead of firms trying to build this capability themselves today, there aren't really many options for this. You want to sort of sell this as open source but support it as well.

Is that where the revenue would come from?

Vasek Mlejnsky1:39:57

So the question is about business model. Yeah. So two parts. It's pretty similar or pretty much any open core business model. So most features are open source. You can self-host it on your own and manage it on your own.

Or you can use our cloud. There will be a few features more targeted for enterprises, especially around we get questions about how do you load terabytes of data into a sandbox. That's not something that you encounter during your weekend hacking or something like that.

And then we are also planning a lot of work on top of observability. Because as the LLMs are getting better, you will want to know what is happening inside a sandbox because it will not be just like running a simple Python script.

It will be more like a workspace, like a permanent workspace for your agent and your AI app. And you kind of want to know what is happening inside the sandbox. Are any files getting created? Is any network request happening?

You want to have programmatic access to this information. And you want to be able to stop the sandbox before it actually happens if you don't like it. So those are some of the things that we are working on next.

And some of them might stay private or behind a license.

Guest1:41:26

What's the timeframe to capture that support? Let's say AWS and having that in your brain.

Vasek Mlejnsky1:41:30

This summer.

Guest1:41:31

This summer.

Vasek Mlejnsky1:41:32

Yeah. Question there.

Guest1:41:34

Most of which you have some knowledge you need to do.

Vasek Mlejnsky1:41:38

Yeah.

Guest1:41:38

And then it's like that's capabilities of data-based data management?

Vasek Mlejnsky1:41:44

So the question is if we have any GPU sandboxes, correct?

Guest1:41:49

Yeah.

Vasek Mlejnsky1:41:49

Yeah. Not at the moment. So that's very intentional because we kind of don't want to go into a whole GPU provider business. And even now, usually, if you are serious about GPU work, you want to offload it to someone who does it really, really well.

And there's a lot of players in the space.

So yeah. The short answer is no. The long answer, it makes sense for the future, but not something that we are focused onright now.

Yeah. Question there.

Guest1:42:26

Yeah. Can you tell people about connecting these cloud data tools to the sandbox? Like what kind of limitations or recommendations?

Vasek Mlejnsky1:42:34

So this cloud what?

Guest1:42:36

You mentioned that you can connect cloud data stores.

Vasek Mlejnsky1:42:39

Oh, yeah. So the question is how you can connect something like S3 or Google Cloud Storage.

Guest1:42:45

What kinds of stores can you connect? What do you recommend?

Vasek Mlejnsky1:42:49

Yeah. So

I will show you. We have a guide for this in our documentation. So currently, you can connect anything that looks like S3 or has S3 API. Mainly, that's Google Cloud Storage.

That's Amazon S3, obviously, or AWS. And Cloudflare's R2. There's a little bit more complicated setup that in the future version of the SDK, it will be just like a simple call that you say, hey, I want to mount this endpoint.

And you need to basically, what we are doing is we are using something called Fuse Protocol for that, which allows you to connect your cloud storage to a file system. And then it sort of looks like basically that it's part of your file system.

But actually, every time you are reading or writing to a file inside a cloud storage, you are making a network request. But the nice thing about that, especially if you are a more enterprise customer and

you care about your users' data, is that the data doesn't really leave your storage.

Yeah. Question.

Guest1:44:13

So I understand you're using VMs with Firecracker. Is there a reason you're not planning on using containers instead? I get that they're doing the heavy lifting for you now.

Vasek Mlejnsky1:44:23

So the question is if there's any reason or what is the reason we are not using containers. I have a separate presentation on that. And the short answer is security. So

when customers come to us, they come to us 90%, it's an in-house solution that's either serverless functional, like a Lambda function, or they are managing a fleet of containers or something like that with Kubernetes.

And you can sort of make containers secure. It just needs more work. And you then want things like running Docker in Docker. It's hard to run, for example, Docker inside Docker. It's doable, but it's just like more pain.

And so ergonomics and security is part of the answer where we eventually figure out, hey, if we make an ability to get you a VM really, really fast, you will just get a full computer for your LLM, which is like a nice win.

And there's nothing you need to do special. It's just like a Linux machine. The second part of this answer is something we don't have implemented yet, but we think will be super important. And that's snapshots.

With Firecracker and a few other VM projects out there, you can very easily make a snapshot of the whole VM at its current state, and not only file system, but also memory. And you can do it pretty fast.

It takes, again, I think like 80 milliseconds or something like that. And we think it will be super important in the future, especially once LLMs get more capable and cheaper. You will want to go into sort of this tree search problem where you can let many agents, versions of your AI app, explore the whole space.

And every time, if you imagine like a graph or like a tree, every node would be like a snapshot of that VM. And you can come back to it and load it again. So you bring sort of this

a little bit of deterministicism into a non-deterministic system because you can just save it at any point and come back to it. And we can also save it and prevent your agent from doing anything you don't like.

And just one last note is that something like this is sort of possible with Docker containers. It's just like the technology isn't really finished. It's like half working, half not working. It's called Creu, C-R-I-U.

Yeah. If anyone has any last question, now is the time. If not, thank you for following me and coding along. And if you want to ask any question like one-to-one to me, feel free to catch me in the hallway or send us a message on Discord or just email me.

It's on E2B. It's vasek@e2b.dev. Thank you.