Skip to content

Commit

Permalink
refactor: consolidate runtime startup command into an util function (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
xingyaoww authored Jan 10, 2025
1 parent a622d27 commit 828d169
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 104 deletions.
32 changes: 9 additions & 23 deletions openhands/runtime/impl/docker/docker_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from openhands.runtime.impl.docker.containers import remove_all_containers
from openhands.runtime.plugins import PluginRequirement
from openhands.runtime.utils import find_available_tcp_port
from openhands.runtime.utils.command import get_action_execution_server_startup_command
from openhands.runtime.utils.log_streamer import LogStreamer
from openhands.runtime.utils.runtime_build import build_runtime_image
from openhands.utils.async_utils import call_sync_from_async
Expand Down Expand Up @@ -186,11 +187,7 @@ def _init_docker_client() -> docker.DockerClient:
def _init_container(self):
self.log('debug', 'Preparing to start container...')
self.send_status_message('STATUS$PREPARING_CONTAINER')
plugin_arg = ''
if self.plugins is not None and len(self.plugins) > 0:
plugin_arg = (
f'--plugins {" ".join([plugin.name for plugin in self.plugins])} '
)

self._host_port = self._find_available_port(EXECUTION_SERVER_PORT_RANGE)
self._container_port = self._host_port
self._vscode_port = self._find_available_port(VSCODE_PORT_RANGE)
Expand All @@ -203,8 +200,6 @@ def _init_container(self):
use_host_network = self.config.sandbox.use_host_network
network_mode: str | None = 'host' if use_host_network else None

use_host_network = self.config.sandbox.use_host_network

# Initialize port mappings
port_mapping: dict[str, list[dict[str, str]]] | None = None
if not use_host_network:
Expand Down Expand Up @@ -257,26 +252,17 @@ def _init_container(self):
f'Sandbox workspace: {self.config.workspace_mount_path_in_sandbox}',
)

if self.config.sandbox.browsergym_eval_env is not None:
browsergym_arg = (
f'--browsergym-eval-env {self.config.sandbox.browsergym_eval_env}'
)
else:
browsergym_arg = ''
command = get_action_execution_server_startup_command(
server_port=self._container_port,
plugins=self.plugins,
app_config=self.config,
use_nice_for_root=False,
)

try:
self.container = self.docker_client.containers.run(
self.runtime_container_image,
command=(
f'/openhands/micromamba/bin/micromamba run -n openhands '
f'poetry run '
f'python -u -m openhands.runtime.action_execution_server {self._container_port} '
f'--working-dir "{self.config.workspace_mount_path_in_sandbox}" '
f'{plugin_arg}'
f'--username {"openhands" if self.config.run_as_openhands else "root"} '
f'--user-id {self.config.sandbox.user_id} '
f'{browsergym_arg}'
),
command=command,
network_mode=network_mode,
ports=port_mapping,
working_dir='/openhands/code/', # do not change this!
Expand Down
26 changes: 5 additions & 21 deletions openhands/runtime/impl/modal/modal_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
ActionExecutionClient,
)
from openhands.runtime.plugins import PluginRequirement
from openhands.runtime.utils.command import get_remote_startup_command
from openhands.runtime.utils.command import get_action_execution_server_startup_command
from openhands.runtime.utils.runtime_build import (
BuildFromImageType,
prep_build_folder,
Expand Down Expand Up @@ -203,11 +203,6 @@ def _init_sandbox(
):
try:
self.log('debug', 'Preparing to start container...')
plugin_args = []
if plugins is not None and len(plugins) > 0:
plugin_args.append('--plugins')
plugin_args.extend([plugin.name for plugin in plugins])

# Combine environment variables
environment: dict[str, str | None] = {
'port': str(self.container_port),
Expand All @@ -216,24 +211,13 @@ def _init_sandbox(
if self.config.debug:
environment['DEBUG'] = 'true'

browsergym_args = []
if self.config.sandbox.browsergym_eval_env is not None:
browsergym_args = [
'-browsergym-eval-env',
self.config.sandbox.browsergym_eval_env,
]

env_secret = modal.Secret.from_dict(environment)

self.log('debug', f'Sandbox workspace: {sandbox_workspace_dir}')
sandbox_start_cmd = get_remote_startup_command(
self.container_port,
sandbox_workspace_dir,
'openhands' if self.config.run_as_openhands else 'root',
self.config.sandbox.user_id,
plugin_args,
browsergym_args,
is_root=not self.config.run_as_openhands, # is_root=True when running as root
sandbox_start_cmd = get_action_execution_server_startup_command(
server_port=self.container_port,
plugins=self.plugins,
app_config=self.config,
)
self.log('debug', f'Starting container with command: {sandbox_start_cmd}')
self.sandbox = modal.Sandbox.create(
Expand Down
22 changes: 5 additions & 17 deletions openhands/runtime/impl/remote/remote_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
ActionExecutionClient,
)
from openhands.runtime.plugins import PluginRequirement
from openhands.runtime.utils.command import get_remote_startup_command
from openhands.runtime.utils.command import get_action_execution_server_startup_command
from openhands.runtime.utils.request import send_request
from openhands.runtime.utils.runtime_build import build_runtime_image
from openhands.utils.async_utils import call_sync_from_async
Expand Down Expand Up @@ -194,22 +194,10 @@ def _build_runtime(self):

def _start_runtime(self):
# Prepare the request body for the /start endpoint
plugin_args = []
if self.plugins is not None and len(self.plugins) > 0:
plugin_args = ['--plugins'] + [plugin.name for plugin in self.plugins]
browsergym_args = []
if self.config.sandbox.browsergym_eval_env is not None:
browsergym_args = [
'--browsergym-eval-env'
] + self.config.sandbox.browsergym_eval_env.split(' ')
command = get_remote_startup_command(
self.port,
self.config.workspace_mount_path_in_sandbox,
'openhands' if self.config.run_as_openhands else 'root',
self.config.sandbox.user_id,
plugin_args,
browsergym_args,
is_root=not self.config.run_as_openhands, # is_root=True when running as root
command = get_action_execution_server_startup_command(
server_port=self.port,
plugins=self.plugins,
app_config=self.config,
)
start_request = {
'image': self.container_image,
Expand Down
28 changes: 5 additions & 23 deletions openhands/runtime/impl/runloop/runloop_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
ActionExecutionClient,
)
from openhands.runtime.plugins import PluginRequirement
from openhands.runtime.utils.command import get_remote_startup_command
from openhands.runtime.utils.command import get_action_execution_server_startup_command
from openhands.utils.tenacity_stop import stop_if_should_exit

CONTAINER_NAME_PREFIX = 'openhands-runtime-'
Expand Down Expand Up @@ -78,28 +78,10 @@ def _wait_for_devbox(self, devbox: DevboxView) -> DevboxView:

def _create_new_devbox(self) -> DevboxView:
# Note: Runloop connect
sandbox_workspace_dir = self.config.workspace_mount_path_in_sandbox
plugin_args = []
if self.plugins is not None and len(self.plugins) > 0:
plugin_args.append('--plugins')
plugin_args.extend([plugin.name for plugin in self.plugins])

browsergym_args = []
if self.config.sandbox.browsergym_eval_env is not None:
browsergym_args = [
'-browsergym-eval-env',
self.config.sandbox.browsergym_eval_env,
]

# Copied from EventstreamRuntime
start_command = get_remote_startup_command(
self._sandbox_port,
sandbox_workspace_dir,
'openhands' if self.config.run_as_openhands else 'root',
self.config.sandbox.user_id,
plugin_args,
browsergym_args,
is_root=not self.config.run_as_openhands, # is_root=True when running as root
start_command = get_action_execution_server_startup_command(
server_port=self._sandbox_port,
plugins=self.plugins,
app_config=self.config,
)

# Add some additional commands based on our image
Expand Down
62 changes: 42 additions & 20 deletions openhands/runtime/utils/command.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,57 @@
def get_remote_startup_command(
port: int,
sandbox_workspace_dir: str,
username: str,
user_id: int,
plugin_args: list[str],
browsergym_args: list[str],
is_root: bool = False,
from openhands.core.config import AppConfig
from openhands.runtime.plugins import PluginRequirement

DEFAULT_PYTHON_PREFIX = [
'/openhands/micromamba/bin/micromamba',
'run',
'-n',
'openhands',
'poetry',
'run',
]


def get_action_execution_server_startup_command(
server_port: int,
plugins: list[PluginRequirement],
app_config: AppConfig,
python_prefix: list[str] = DEFAULT_PYTHON_PREFIX,
use_nice_for_root: bool = True,
):
sandbox_config = app_config.sandbox

# Plugin args
plugin_args = []
if plugins is not None and len(plugins) > 0:
plugin_args = ['--plugins'] + [plugin.name for plugin in plugins]

# Browsergym stuffs
browsergym_args = []
if sandbox_config.browsergym_eval_env is not None:
browsergym_args = [
'--browsergym-eval-env'
] + sandbox_config.browsergym_eval_env.split(' ')

is_root = not app_config.run_as_openhands

base_cmd = [
'/openhands/micromamba/bin/micromamba',
'run',
'-n',
'openhands',
'poetry',
'run',
*python_prefix,
'python',
'-u',
'-m',
'openhands.runtime.action_execution_server',
str(port),
str(server_port),
'--working-dir',
sandbox_workspace_dir,
app_config.workspace_mount_path_in_sandbox,
*plugin_args,
'--username',
username,
'openhands' if app_config.run_as_openhands else 'root',
'--user-id',
str(user_id),
str(sandbox_config.user_id),
*browsergym_args,
]

if is_root:
if is_root and use_nice_for_root:
# If running as root, set highest priority and lowest OOM score
cmd_str = ' '.join(base_cmd)
return [
Expand All @@ -41,5 +63,5 @@ def get_remote_startup_command(
f'echo -1000 > /proc/self/oom_score_adj && exec {cmd_str}',
]
else:
# If not root, run with normal priority
# If not root OR not using nice for root, run with normal priority
return base_cmd

0 comments on commit 828d169

Please sign in to comment.