Skip to content

Commit c7dff3e

Browse files
neubigopenhands-agentenyst
authored
Remove third-party runtimes (daytona, modal, e2b, runloop) from main codebase (#9213)
Co-authored-by: openhands <[email protected]> Co-authored-by: Engel Nyst <[email protected]> Co-authored-by: Engel Nyst <[email protected]>
1 parent 6efb992 commit c7dff3e

35 files changed

+251
-147
lines changed

config.template.toml

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,7 @@
1010
# General core configurations
1111
##############################################################################
1212
[core]
13-
# API key for E2B
14-
#e2b_api_key = ""
15-
16-
# API key for Modal
17-
#modal_api_token_id = ""
18-
#modal_api_token_secret = ""
19-
20-
# API key for Daytona
21-
#daytona_api_key = ""
22-
23-
# Daytona Target
24-
#daytona_target = ""
13+
# API keys and configuration for core services
2514

2615
# Base path for the workspace
2716
#workspace_base = "./workspace"

dev_config/python/.pre-commit-config.yaml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ repos:
33
rev: v5.0.0
44
hooks:
55
- id: trailing-whitespace
6-
exclude: ^(docs/|modules/|python/|openhands-ui/)
6+
exclude: ^(docs/|modules/|python/|openhands-ui/|third_party/)
77
- id: end-of-file-fixer
8-
exclude: ^(docs/|modules/|python/|openhands-ui/)
8+
exclude: ^(docs/|modules/|python/|openhands-ui/|third_party/)
99
- id: check-yaml
1010
args: ["--allow-multiple-documents"]
1111
- id: debug-statements
@@ -28,10 +28,12 @@ repos:
2828
entry: ruff check --config dev_config/python/ruff.toml
2929
types_or: [python, pyi, jupyter]
3030
args: [--fix, --unsafe-fixes]
31+
exclude: third_party/
3132
# Run the formatter.
3233
- id: ruff-format
3334
entry: ruff format --config dev_config/python/ruff.toml
3435
types_or: [python, pyi, jupyter]
36+
exclude: third_party/
3537

3638
- repo: https://github.com/pre-commit/mirrors-mypy
3739
rev: v1.15.0

dev_config/python/mypy.ini

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@ warn_unreachable = True
77
warn_redundant_casts = True
88
no_implicit_optional = True
99
strict_optional = True
10+
# Exclude third-party runtime directory from type checking
11+
exclude = third_party/

dev_config/python/ruff.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# Exclude third-party runtime directory from linting
2+
exclude = ["third_party/"]
3+
14
[lint]
25
select = [
36
"E",

docs/usage/configuration-options.mdx

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,6 @@ description: This page outlines all available configuration options for OpenHand
1212

1313
The core configuration options are defined in the `[core]` section of the `config.toml` file.
1414

15-
### API Keys
16-
- `e2b_api_key`
17-
- Type: `str`
18-
- Default: `""`
19-
- Description: API key for E2B
20-
21-
- `modal_api_token_id`
22-
- Type: `str`
23-
- Default: `""`
24-
- Description: API token ID for Modal
25-
26-
- `modal_api_token_secret`
27-
- Type: `str`
28-
- Default: `""`
29-
- Description: API token secret for Modal
30-
3115
### Workspace
3216
- `workspace_base` **(Deprecated)**
3317
- Type: `str`

docs/usage/runtimes/overview.mdx

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ commands.
99
By default, OpenHands uses a [Docker-based runtime](/usage/runtimes/docker), running on your local computer.
1010
This means you only have to pay for the LLM you're using, and your code is only ever sent to the LLM.
1111

12-
We also support other runtimes, which are typically managed by third-parties.
13-
1412
Additionally, we provide a [Local Runtime](/usage/runtimes/local) that runs directly on your machine without Docker,
1513
which can be useful in controlled environments like CI pipelines.
1614

@@ -21,6 +19,18 @@ OpenHands supports several different runtime environments:
2119
- [Docker Runtime](/usage/runtimes/docker) - The default runtime that uses Docker containers for isolation (recommended for most users).
2220
- [OpenHands Remote Runtime](/usage/runtimes/remote) - Cloud-based runtime for parallel execution (beta).
2321
- [Local Runtime](/usage/runtimes/local) - Direct execution on your local machine without Docker.
24-
- And more third-party runtimes:
25-
- [Modal Runtime](/usage/runtimes/modal) - Runtime provided by our partners at Modal.
26-
- [Daytona Runtime](/usage/runtimes/daytona) - Runtime provided by Daytona.
22+
23+
### Third-Party Runtimes
24+
25+
The following third-party runtimes are available when you install the `third_party_runtimes` extra:
26+
27+
```bash
28+
pip install openhands-ai[third_party_runtimes]
29+
```
30+
31+
- [E2B Runtime](/usage/runtimes/e2b) - Open source runtime using E2B sandboxes.
32+
- [Modal Runtime](/usage/runtimes/modal) - Serverless runtime using Modal infrastructure.
33+
- [Runloop Runtime](/usage/runtimes/runloop) - Cloud runtime using Runloop infrastructure.
34+
- [Daytona Runtime](/usage/runtimes/daytona) - Development environment runtime using Daytona.
35+
36+
**Note**: These third-party runtimes are supported by their respective developers, not by the OpenHands team. For issues specific to these runtimes, please refer to their documentation or contact their support teams.

openhands/core/config/openhands_config.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ class OpenHandsConfig(BaseModel):
4646
run_as_openhands: Whether to run as openhands.
4747
max_iterations: Maximum number of iterations allowed.
4848
max_budget_per_task: Maximum budget per task, agent stops if exceeded.
49-
e2b_api_key: E2B API key.
5049
disable_color: Whether to disable terminal colors. For terminals that don't support color.
5150
debug: Whether to enable debugging mode.
5251
file_uploads_max_file_size_mb: Maximum file upload size in MB. `0` means unlimited.
@@ -88,19 +87,14 @@ class OpenHandsConfig(BaseModel):
8887
run_as_openhands: bool = Field(default=True)
8988
max_iterations: int = Field(default=OH_MAX_ITERATIONS)
9089
max_budget_per_task: float | None = Field(default=None)
91-
e2b_api_key: SecretStr | None = Field(default=None)
92-
modal_api_token_id: SecretStr | None = Field(default=None)
93-
modal_api_token_secret: SecretStr | None = Field(default=None)
90+
9491
disable_color: bool = Field(default=False)
9592
jwt_secret: SecretStr | None = Field(default=None)
9693
debug: bool = Field(default=False)
9794
file_uploads_max_file_size_mb: int = Field(default=0)
9895
file_uploads_restrict_file_types: bool = Field(default=False)
9996
file_uploads_allowed_extensions: list[str] = Field(default_factory=lambda: ['.*'])
100-
runloop_api_key: SecretStr | None = Field(default=None)
101-
daytona_api_key: SecretStr | None = Field(default=None)
102-
daytona_api_url: str = Field(default='https://app.daytona.io/api')
103-
daytona_target: str = Field(default='eu')
97+
10498
cli_multiline_input: bool = Field(default=False)
10599
conversation_max_age_seconds: int = Field(default=864000) # 10 days in seconds
106100
enable_default_condenser: bool = Field(default=True)

openhands/core/logger.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ def filter(self, record: logging.LogRecord) -> bool:
261261
'modal_api_token_secret',
262262
'llm_api_key',
263263
'sandbox_env_github_token',
264+
'runloop_api_key',
264265
'daytona_api_key',
265266
]
266267

openhands/runtime/__init__.py

Lines changed: 70 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,113 @@
1+
import importlib
2+
13
from openhands.runtime.base import Runtime
24
from openhands.runtime.impl.cli.cli_runtime import CLIRuntime
3-
from openhands.runtime.impl.daytona.daytona_runtime import DaytonaRuntime
45
from openhands.runtime.impl.docker.docker_runtime import (
56
DockerRuntime,
67
)
7-
from openhands.runtime.impl.e2b.e2b_runtime import E2BRuntime
88
from openhands.runtime.impl.kubernetes.kubernetes_runtime import KubernetesRuntime
99
from openhands.runtime.impl.local.local_runtime import LocalRuntime
10-
from openhands.runtime.impl.modal.modal_runtime import ModalRuntime
1110
from openhands.runtime.impl.remote.remote_runtime import RemoteRuntime
12-
from openhands.runtime.impl.runloop.runloop_runtime import RunloopRuntime
1311
from openhands.utils.import_utils import get_impl
1412

1513
# mypy: disable-error-code="type-abstract"
1614
_DEFAULT_RUNTIME_CLASSES: dict[str, type[Runtime]] = {
1715
'eventstream': DockerRuntime,
1816
'docker': DockerRuntime,
19-
'e2b': E2BRuntime,
2017
'remote': RemoteRuntime,
21-
'modal': ModalRuntime,
22-
'runloop': RunloopRuntime,
2318
'local': LocalRuntime,
24-
'daytona': DaytonaRuntime,
2519
'kubernetes': KubernetesRuntime,
2620
'cli': CLIRuntime,
2721
}
2822

23+
# Try to import third-party runtimes if available
24+
_THIRD_PARTY_RUNTIME_CLASSES: dict[str, type[Runtime]] = {}
25+
26+
# Dynamically discover and import third-party runtimes
27+
28+
# Check if third_party package exists and discover runtimes
29+
try:
30+
import third_party.runtime.impl
31+
32+
third_party_base = 'third_party.runtime.impl'
33+
34+
# List of potential third-party runtime modules to try
35+
# These are discovered from the third_party directory structure
36+
potential_runtimes = []
37+
try:
38+
import pkgutil
39+
40+
for importer, modname, ispkg in pkgutil.iter_modules(
41+
third_party.runtime.impl.__path__
42+
):
43+
if ispkg:
44+
potential_runtimes.append(modname)
45+
except Exception:
46+
# If discovery fails, no third-party runtimes will be loaded
47+
potential_runtimes = []
48+
49+
# Try to import each discovered runtime
50+
for runtime_name in potential_runtimes:
51+
try:
52+
module_path = f'{third_party_base}.{runtime_name}.{runtime_name}_runtime'
53+
module = importlib.import_module(module_path)
54+
55+
# Try different class name patterns
56+
possible_class_names = [
57+
f'{runtime_name.upper()}Runtime', # E2BRuntime
58+
f'{runtime_name.capitalize()}Runtime', # E2bRuntime, DaytonaRuntime, etc.
59+
]
60+
61+
runtime_class = None
62+
for class_name in possible_class_names:
63+
try:
64+
runtime_class = getattr(module, class_name)
65+
break
66+
except AttributeError:
67+
continue
68+
69+
if runtime_class:
70+
_THIRD_PARTY_RUNTIME_CLASSES[runtime_name] = runtime_class
71+
72+
except ImportError:
73+
pass
74+
75+
except ImportError:
76+
# third_party package not available
77+
pass
78+
79+
# Combine core and third-party runtimes
80+
_ALL_RUNTIME_CLASSES = {**_DEFAULT_RUNTIME_CLASSES, **_THIRD_PARTY_RUNTIME_CLASSES}
81+
2982

3083
def get_runtime_cls(name: str) -> type[Runtime]:
3184
"""
3285
If name is one of the predefined runtime names (e.g. 'docker'), return its class.
3386
Otherwise attempt to resolve name as subclass of Runtime and return it.
3487
Raise on invalid selections.
3588
"""
36-
if name in _DEFAULT_RUNTIME_CLASSES:
37-
return _DEFAULT_RUNTIME_CLASSES[name]
89+
if name in _ALL_RUNTIME_CLASSES:
90+
return _ALL_RUNTIME_CLASSES[name]
3891
try:
3992
return get_impl(Runtime, name)
4093
except Exception as e:
41-
known_keys = _DEFAULT_RUNTIME_CLASSES.keys()
94+
known_keys = _ALL_RUNTIME_CLASSES.keys()
4295
raise ValueError(
4396
f'Runtime {name} not supported, known are: {known_keys}'
4497
) from e
4598

4699

100+
# Build __all__ list dynamically based on available runtimes
47101
__all__ = [
48102
'Runtime',
49-
'E2BRuntime',
50103
'RemoteRuntime',
51-
'ModalRuntime',
52-
'RunloopRuntime',
53104
'DockerRuntime',
54-
'DaytonaRuntime',
55105
'KubernetesRuntime',
56106
'CLIRuntime',
107+
'LocalRuntime',
57108
'get_runtime_cls',
58109
]
110+
111+
# Add third-party runtimes to __all__ if they're available
112+
for runtime_name, runtime_class in _THIRD_PARTY_RUNTIME_CLASSES.items():
113+
__all__.append(runtime_class.__name__)

openhands/runtime/base.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,10 @@ class Runtime(FileEditRuntimeMixin):
100100
101101
Built-in implementations include:
102102
- DockerRuntime: Containerized environment using Docker
103-
- E2BRuntime: Secure sandbox using E2B
104103
- RemoteRuntime: Remote execution environment
105-
- ModalRuntime: Scalable cloud environment using Modal
106104
- LocalRuntime: Local execution for development
107-
- DaytonaRuntime: Cloud development environment using Daytona
105+
- KubernetesRuntime: Kubernetes-based execution environment
106+
- CLIRuntime: Command-line interface runtime
108107
109108
Args:
110109
sid: Session ID that uniquely identifies the current user session

openhands/runtime/impl/__init__.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,14 @@
66
ActionExecutionClient,
77
)
88
from openhands.runtime.impl.cli import CLIRuntime
9-
from openhands.runtime.impl.daytona.daytona_runtime import DaytonaRuntime
109
from openhands.runtime.impl.docker.docker_runtime import DockerRuntime
11-
from openhands.runtime.impl.e2b.e2b_runtime import E2BRuntime
1210
from openhands.runtime.impl.local.local_runtime import LocalRuntime
13-
from openhands.runtime.impl.modal.modal_runtime import ModalRuntime
1411
from openhands.runtime.impl.remote.remote_runtime import RemoteRuntime
15-
from openhands.runtime.impl.runloop.runloop_runtime import RunloopRuntime
1612

1713
__all__ = [
1814
'ActionExecutionClient',
1915
'CLIRuntime',
20-
'DaytonaRuntime',
2116
'DockerRuntime',
22-
'E2BRuntime',
2317
'LocalRuntime',
24-
'ModalRuntime',
2518
'RemoteRuntime',
26-
'RunloopRuntime',
2719
]

0 commit comments

Comments
 (0)