diff --git a/enterprise/server/saas_nested_conversation_manager.py b/enterprise/server/saas_nested_conversation_manager.py index 0c5ece2675..d92e67b9ff 100644 --- a/enterprise/server/saas_nested_conversation_manager.py +++ b/enterprise/server/saas_nested_conversation_manager.py @@ -31,6 +31,7 @@ from openhands.events.event_store import EventStore from openhands.events.serialization.event import event_to_dict from openhands.integrations.provider import PROVIDER_TOKEN_TYPE, ProviderHandler from openhands.runtime.impl.remote.remote_runtime import RemoteRuntime +from openhands.runtime.plugins.vscode import VSCodeRequirement from openhands.runtime.runtime_status import RuntimeStatus from openhands.server.config.server_config import ServerConfig from openhands.server.constants import ROOM_KEY @@ -71,10 +72,13 @@ RUNTIME_CONVERSATION_URL = RUNTIME_URL_PATTERN + ( ) RUNTIME_USERNAME = os.getenv('RUNTIME_USERNAME') + SU_TO_USER = os.getenv('SU_TO_USER', 'false') truthy = {'1', 'true', 't', 'yes', 'y', 'on'} SU_TO_USER = str(SU_TO_USER.lower() in truthy).lower() +DISABLE_VSCODE_PLUGIN = os.getenv('DISABLE_VSCODE_PLUGIN', 'false').lower() == 'true' + # Time in seconds before a Redis entry is considered expired if not refreshed _REDIS_ENTRY_TIMEOUT_SECONDS = 300 @@ -799,6 +803,7 @@ class SaasNestedConversationManager(ConversationManager): env_vars['INIT_GIT_IN_EMPTY_WORKSPACE'] = '1' env_vars['ENABLE_V1'] = '0' env_vars['SU_TO_USER'] = SU_TO_USER + env_vars['DISABLE_VSCODE_PLUGIN'] = str(DISABLE_VSCODE_PLUGIN).lower() # We need this for LLM traces tracking to identify the source of the LLM calls env_vars['WEB_HOST'] = WEB_HOST @@ -814,11 +819,18 @@ class SaasNestedConversationManager(ConversationManager): if self._runtime_container_image: config.sandbox.runtime_container_image = self._runtime_container_image + plugins = [ + plugin + for plugin in agent.sandbox_plugins + if not (DISABLE_VSCODE_PLUGIN and isinstance(plugin, VSCodeRequirement)) + ] + logger.info(f'Loaded plugins for runtime {sid}: {plugins}') + runtime = RemoteRuntime( config=config, event_stream=None, # type: ignore[arg-type] sid=sid, - plugins=agent.sandbox_plugins, + plugins=plugins, # env_vars=env_vars, # status_callback: Callable[..., None] | None = None, attach_to_existing=False, diff --git a/openhands/runtime/base.py b/openhands/runtime/base.py index 5eb5429f71..c7a332166b 100644 --- a/openhands/runtime/base.py +++ b/openhands/runtime/base.py @@ -76,6 +76,8 @@ from openhands.utils.async_utils import ( call_sync_from_async, ) +DISABLE_VSCODE_PLUGIN = os.getenv('DISABLE_VSCODE_PLUGIN', 'false').lower() == 'true' + def _default_env_vars(sandbox_config: SandboxConfig) -> dict[str, str]: ret = {} @@ -153,9 +155,11 @@ class Runtime(FileEditRuntimeMixin): self.plugins = ( copy.deepcopy(plugins) if plugins is not None and len(plugins) > 0 else [] ) + # add VSCode plugin if not in headless mode - if not headless_mode: + if not headless_mode and not DISABLE_VSCODE_PLUGIN: self.plugins.append(VSCodeRequirement()) + logger.info(f'Loaded plugins for runtime {self.sid}: {self.plugins}') self.status_callback = status_callback self.attach_to_existing = attach_to_existing diff --git a/openhands/runtime/impl/local/local_runtime.py b/openhands/runtime/impl/local/local_runtime.py index ed8d26996a..f6ef26a1cf 100644 --- a/openhands/runtime/impl/local/local_runtime.py +++ b/openhands/runtime/impl/local/local_runtime.py @@ -45,6 +45,8 @@ from openhands.utils.async_utils import call_sync_from_async from openhands.utils.http_session import httpx_verify_option from openhands.utils.tenacity_stop import stop_if_should_exit +DISABLE_VSCODE_PLUGIN = os.getenv('DISABLE_VSCODE_PLUGIN', 'false').lower() == 'true' + @dataclass class ActionExecutionServerInfo: @@ -406,7 +408,7 @@ class LocalRuntime(ActionExecutionClient): plugins = _get_plugins(config) # Copy the logic from Runtime where we add a VSCodePlugin on init if missing - if not headless_mode: + if not headless_mode and not DISABLE_VSCODE_PLUGIN: plugins.append(VSCodeRequirement()) for _ in range(initial_num_warm_servers):