feat: Add Windows PowerShell support to CLI runtime (#9211)

Co-authored-by: openhands <openhands@all-hands.dev>
This commit is contained in:
Graham Neubig
2025-06-22 20:17:40 -04:00
committed by GitHub
parent 081880248c
commit 5d69e606eb
4 changed files with 202 additions and 21 deletions

View File

@@ -21,21 +21,31 @@ from openhands.events.observation.commands import (
CmdOutputObservation,
)
from openhands.runtime.utils.bash_constants import TIMEOUT_MESSAGE_TEMPLATE
from openhands.runtime.utils.windows_exceptions import DotNetMissingError
from openhands.utils.shutdown_listener import should_continue
pythonnet.load('coreclr')
logger.info("Successfully called pythonnet.load('coreclr')")
# Now that pythonnet is initialized, import clr and System
try:
import clr
pythonnet.load('coreclr')
logger.info("Successfully called pythonnet.load('coreclr')")
logger.debug(f'Imported clr module from: {clr.__file__}')
# Load System assembly *after* pythonnet is initialized
clr.AddReference('System')
import System
except Exception as clr_sys_ex:
raise RuntimeError(f'FATAL: Failed to import clr or System. Error: {clr_sys_ex}')
# Now that pythonnet is initialized, import clr and System
try:
import clr
logger.debug(f'Imported clr module from: {clr.__file__}')
# Load System assembly *after* pythonnet is initialized
clr.AddReference('System')
import System
except Exception as clr_sys_ex:
error_msg = 'Failed to import .NET components.'
details = str(clr_sys_ex)
logger.error(f'{error_msg} Details: {details}')
raise DotNetMissingError(error_msg, details)
except Exception as coreclr_ex:
error_msg = 'Failed to load CoreCLR.'
details = str(coreclr_ex)
logger.error(f'{error_msg} Details: {details}')
raise DotNetMissingError(error_msg, details)
# Attempt to load the PowerShell SDK assembly only if clr and System loaded
ps_sdk_path = None
@@ -78,9 +88,10 @@ try:
RunspaceState,
)
except Exception as e:
raise RuntimeError(
f'FATAL: Failed to load PowerShell SDK components. Error: {e}. Check pythonnet installation and .NET Runtime compatibility. Path searched: {ps_sdk_path}'
)
error_msg = 'Failed to load PowerShell SDK components.'
details = f'{str(e)} (Path searched: {ps_sdk_path})'
logger.error(f'{error_msg} Details: {details}')
raise DotNetMissingError(error_msg, details)
class WindowsPowershellSession:
@@ -115,9 +126,11 @@ class WindowsPowershellSession:
if PowerShell is None: # Check if SDK loading failed during module import
# Logged critical error during import, just raise here to prevent instantiation
raise RuntimeError(
'PowerShell SDK (System.Management.Automation.dll) could not be loaded. Cannot initialize WindowsPowershellSession.'
error_msg = (
'PowerShell SDK (System.Management.Automation.dll) could not be loaded.'
)
logger.error(error_msg)
raise DotNetMissingError(error_msg)
self.work_dir = os.path.abspath(work_dir)
self.username = username

View File

@@ -0,0 +1,15 @@
"""
Custom exceptions for Windows-specific runtime issues.
"""
class DotNetMissingError(Exception):
"""
Exception raised when .NET SDK or CoreCLR is missing or cannot be loaded.
This is used to provide a cleaner error message to users without a full stack trace.
"""
def __init__(self, message: str, details: str | None = None):
self.message = message
self.details = details
super().__init__(message)