Implement basic modal sandbox support
This commit adds modal sandbox support via the remote image runtime.
- [x] Include this change in the Release Notes. If checked, you must provide an end-user friendly description for your change below
End-user friendly description of the problem this fixes or functionality that this introduces
Adds support for modal sandboxes as the execution runtime. To use this, create an API token and add the appropriate values to your config.toml:
# API key for Modal
[core]
modal_api_token_id = "<id>"
modal_api_token_secret = "<secret>"
runtime = "modal"
[sandbox]
runtime_container_image = "ghcr.io/all-hands-ai/runtime:0.9-nikolaik"
Give a summary of what the PR does, explaining any non-trivial design decisions
This PR adds Modal sandbox support as a new runtime. I'm looking for feedback on this work - specifically, I'm looking for feedback on how to factor out the unique logic and reuse as much as possible from the existing remote runtime code. This file is identical to openhands/runtime/client/runtime.py except for:
- Container lifecycle control (startup/teardown)
- Log propagation source (the log retrieval logic is the same, but the source is different)
The diff is currently quite large, but I think with some refactoring it can be very small.
Link of any specific issues this addresses
I had to make a few modifications to the integration test runtime to get this working. Notably:
- Since remote runtimes can't do bind mounts, I manually copied the files over and back before/after the tests.
- I started up the http server inside the container for the browsing tests.
I think both these should not be where I put them - I put them in the main runtime function. Instead I think the runtime function should provide pre/post action hooks that I can use to do lifecycle-style actions. But I'll look for feedback on this work before going down that rabbit hole.
This is ready for a re-review. I've removed my changes that made integration tests work.
@pawalt - I think in openhands/core/config/app_config.py you need to add modal_api_token_id to the __str__ method.
Also, openhands/core/logger.py -> SensitiveDataFilter()
Thanks @pawalt!