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

feat: vscode support for modal runtime #6442

Merged
merged 2 commits into from
Jan 24, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion openhands/runtime/impl/modal/modal_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class ModalRuntime(ActionExecutionClient):

container_name_prefix = 'openhands-sandbox-'
sandbox: modal.Sandbox | None
sid: str

def __init__(
self,
Expand All @@ -57,6 +58,7 @@ def __init__(

self.config = config
self.sandbox = None
self.sid = sid

self.modal_client = modal.Client.from_credentials(
config.modal_api_token_id.get_secret_value(),
Expand All @@ -75,6 +77,8 @@ def __init__(

# This value is arbitrary as it's private to the container
self.container_port = 3000
self._vscode_port = 4445
self._vscode_url: str | None = None

self.status_callback = status_callback
self.base_container_image_id = self.config.sandbox.base_container_image
Expand Down Expand Up @@ -140,6 +144,7 @@ async def connect(self):

if not self.attach_to_existing:
self.send_status_message(' ')
self._runtime_initialized = True

def _get_action_execution_server_host(self):
return self.api_url
Expand Down Expand Up @@ -208,6 +213,7 @@ def _init_sandbox(
environment: dict[str, str | None] = {
'port': str(self.container_port),
'PYTHONUNBUFFERED': '1',
'VSCODE_PORT': str(self._vscode_port),
}
if self.config.debug:
environment['DEBUG'] = 'true'
Expand All @@ -225,7 +231,7 @@ def _init_sandbox(
*sandbox_start_cmd,
secrets=[env_secret],
workdir='/openhands/code',
encrypted_ports=[self.container_port],
encrypted_ports=[self.container_port, self._vscode_port],
image=self.image,
app=self.app,
client=self.modal_client,
Expand All @@ -248,3 +254,27 @@ def close(self):

if not self.attach_to_existing and self.sandbox:
self.sandbox.terminate()

@property
def vscode_url(self) -> str | None:
if self._vscode_url is not None: # cached value
self.log('debug', f'VSCode URL: {self._vscode_url}')
return self._vscode_url
token = super().get_vscode_token()
if not token:
self.log('error', 'VSCode token not found')
return None
if not self.sandbox:
self.log('error', 'Sandbox not initialized')
return None

tunnel = self.sandbox.tunnels()[self._vscode_port]
tunnel_url = tunnel.url
self._vscode_url = tunnel_url + f'/?tkn={token}&folder={self.config.workspace_mount_path_in_sandbox}'

self.log(
'debug',
f'VSCode URL: {self._vscode_url}',
)

return self._vscode_url
Loading