Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integrate E2B sandbox as an alternative to a Docker container #727

Merged
merged 32 commits into from
Apr 19, 2024

Conversation

mlejva
Copy link
Contributor

@mlejva mlejva commented Apr 4, 2024

This is a draft PR for integrating E2B sandbox for OpenDevin's agents. The E2B sandbox is a secure micro VM made for running AI agents and AI generated code in the cloud.

I'll be updating the following todo list as I go:

  • Bring E2B sandbox to the parity in terms of functionality with the current sandbox.py
  • Common interface between Docker container and E2B sandbox
  • Update fileops to happen inside sandbox when using E2B
  • Use E2B sandbox for running swe-bench evals end-to-end (will be done in separate PR)

@foragerr
Copy link
Collaborator

foragerr commented Apr 4, 2024

curious: Can e2b run inside docker?

@mlejva
Copy link
Contributor Author

mlejva commented Apr 4, 2024

curious: Can e2b run inside docker?

No. E2B sandbox is a VM so it sits on a "lower level" compared to a container. What will be possible in the future is to run Docker inside E2B.

Copy link
Collaborator

@rbren rbren left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good!

We can probably formalize the sandbox interface with an abstract class--doesn't need to be in this PR though

opendevin/controller/command_manager.py Outdated Show resolved Hide resolved
opendevin/controller/command_manager.py Outdated Show resolved Hide resolved
@mlejva
Copy link
Contributor Author

mlejva commented Apr 5, 2024

Looking good!

We can probably formalize the sandbox interface with an abstract class--doesn't need to be in this PR though

I'm planning on updating the PR today/tomorrow with proper config and env vars setup and make it match the functionality of the current sandbox.
Once that all will look good to you guys, happy to start working on the common interface.

@mlejva
Copy link
Contributor Author

mlejva commented Apr 7, 2024

@rbren a short update, still work in progress.

I updated the PR so the E2B sandbox matches the functionality of the current Docker sandbox. Specifically the background commands are now supported. Also rebased to main to stay up to date with the new code style rules.

Next step is to:

  • 1. Clean up and improve types so we can build a shared interface between E2B sandbox and Docker sandbox
  • 2. Add config option to allow switching between E2B sandbox and Docker sandbox
  • 3. Enable filesystem operations. Currently, the filesystem operations with Docker sandbox are happening through a mounted volume because the container is running locally. WIth E2B sandbox, everything should happen inside the sandbox - sandbox.filesystem.write('...') - you're interacting right with the filesystem inside the sandbox. We can't currently mount a local folder to the sandbox. I'm thinking introducing a config flag (as mentioned above) to allow users switch sandbox and change how filesystem ops work based on that.

I think I should be able to finish the whole PR this Sunday

@mlejva
Copy link
Contributor Author

mlejva commented Apr 7, 2024

@rbren similar to what @foragerr did in #874 I think we should also build a common interface for process (what's known as command at the moment). It'd be something fairly simple like

from abc import ABC, abstractmethod

class Process(ABC):
    @abstractmethod
    def kill(self):
        pass

    @abstractmethod
    def read_logs(self) -> str:
        pass
    
    @property
    @abstractmethod
    def id(self) -> int:
        pass

    @property
    @abstractmethod
    def command(self) -> str:
        pass

    @property
    @abstractmethod
    def exit_code(self) -> int | None: # The reason it can be none is because the process can still be running
       pass 

What do you think?

@rbren
Copy link
Collaborator

rbren commented Apr 9, 2024

@mlejva that seems reasonable to me!

@mlejva
Copy link
Contributor Author

mlejva commented Apr 9, 2024

curious: Can e2b run inside docker?

@foragerr I realized I might have misunderstood your question. I thought you're talking about self-hosting. With self-hosting what I wrote stands - E2B sandbox is a VM so it sits on a "lower level" compared to a container. What will be possible in the future is to run Docker inside E2B.

But you can definitely use E2B SDK for launching sandboxes in our cloud from Docker and Dockerize the whole app.

I just wanted to clear that up

@mlejva mlejva marked this pull request as ready for review April 13, 2024 02:09
@mlejva mlejva requested a review from rbren April 13, 2024 03:34
@neubig neubig self-requested a review April 14, 2024 01:36
Copy link
Contributor

@neubig neubig left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, thanks a bunch for the contribution! I just have a few small comments.

opendevin/sandbox/__init__.py Outdated Show resolved Hide resolved
opendevin/sandbox/e2b/e2b.Dockerfile Outdated Show resolved Hide resolved
opendevin/sandbox/e2b/sandbox.py Show resolved Hide resolved
opendevin/sandbox/process.py Outdated Show resolved Hide resolved
with open(whole_path, "w", encoding="utf-8") as file:
file.write(self.content)
return FileWriteObservation(content="", path=self.path)
if isinstance(controller.command_manager.sandbox, E2BBox):
Copy link
Collaborator

@rbren rbren Apr 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels leaky to me. But passing controller into run is already kind of leaky. Curious if you have any ideas on how to improve this.

Maybe sandbox should handle all the run logic...

We can come back to this in a future PR

Copy link
Contributor Author

@mlejva mlejva Apr 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I agree this doesn't feel right. Happy to refactorize this once we merge this PR

Copy link
Collaborator

@rbren rbren left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excited to get this in!

@mlejva
Copy link
Contributor Author

mlejva commented Apr 16, 2024

Hey @rbren thank you so much for the code review. I merged the main branch. I'm struggling a bit with understanding why the build didn't pass though.

I built it locally with both Python 3.11 and 3.12 and it looks like it's passing.

Screenshot 2024-04-15 at 11 24 41 PM Screenshot 2024-04-15 at 11 23 31 PM

The errors in GitHub actions seem to only show error code and nothing else though:

Screenshot 2024-04-15 at 11 25 20 PM

I'm not sure why it's not passing, I you have any tips, it would be super helpful!

@mlejva
Copy link
Contributor Author

mlejva commented Apr 16, 2024

I also did a bit of refactorization in this PR.

  • Sandbox is now separated to docker and e2b
  • BackgroundCommand is now Process with separate `
  • I added readme to E2B sandbox to get people started easily
  • I pre-built a custom E2B sandbox for OpenDevin called open-devin.
    • Currently, it's only 0.5GB RAM and 2vCPU and people need to use their on SDK key but once we get OpenDevin to a cloud hosted webapp, we'll upgrade it to better machine, and sponsor all needed compute for OpenDevin's team API key

Copy link
Collaborator

@rbren rbren left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This LGTM as-is! A couple minor notes though


1. Build the sandbox
```sh
e2b template build --dockerfile ./Dockerfile --name "open-devin"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we e2b template from a remote image like ubuntu or ghcr.io/opendevin/sandbox? Or does the user have to build it from scratch?

Would be nice not to have to maintain a new Dockerfile, or to at least build it for them in our CI/CD pipeline

Copy link
Contributor Author

@mlejva mlejva Apr 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can share the same Dockerfile and use a remote image. We just have some restrictions on what images and Dockerfile commands we support. Generally, you should be good. I'll set it up to use the same Dockerfile image

Screenshot 2024-04-16 at 2 53 10 PM

@@ -0,0 +1,14 @@
# This is a config for E2B sandbox template.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see this file getting used anywhere?

Copy link
Contributor Author

@mlejva mlejva Apr 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used by the E2B CLI, it's something like Cloudflare Workers have their wrangler.toml


1. [Get your API key](https://e2b.dev/docs/getting-started/api-key)

1. Set your E2B API key in the `config.toml` file as `E2B_API_KEY`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're mostly getting rid of config.toml now that everything is running inside docker. Maybe this should be passed into docker run with -e?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that should work, I can update it. So config.py isn't used anymore and instead we should pass the env vars, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the readme to instruct users to set the E2B API key to the E2B_API_KEY env var.

If there's nothing else you think should change, this PR should be good to go!

@rbren rbren enabled auto-merge (squash) April 17, 2024 16:14
@rbren
Copy link
Collaborator

rbren commented Apr 17, 2024

auto-merge enabled! 🚀

Thanks for all the work here!

@rbren
Copy link
Collaborator

rbren commented Apr 17, 2024

Sorry, merge conflicts 😭

SWE-agent implemented start and end lines for read/write operations, which I suppose we'll need to support with e2b. Hopefully that's not too hard...

@mlejva
Copy link
Contributor Author

mlejva commented Apr 17, 2024

Sorry, merge conflicts 😭

SWE-agent implemented start and end lines for read/write operations, which I suppose we'll need to support with e2b. Hopefully that's not too hard...

Looking into it in 1-2 hours!

auto-merge was automatically disabled April 18, 2024 20:14

Head branch was pushed to by a user without write access

@mlejva
Copy link
Contributor Author

mlejva commented Apr 18, 2024

Hey @rbren I finally got to resolving the conflicts. Sorry it took longer.
Can you please check it when you have a moment and if it looks good to you merge it?

Thank you!

@rbren rbren enabled auto-merge (squash) April 19, 2024 16:50
auto-merge was automatically disabled April 19, 2024 18:09

Head branch was pushed to by a user without write access

@rbren rbren merged commit 76b81ca into OpenDevin:main Apr 19, 2024
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants