|
|
@@ -62,7 +62,7 @@ from openhands.events.observation import (
|
|
|
from openhands.events.serialization import event_to_dict
|
|
|
from openhands.events.stream import AsyncEventStreamWrapper
|
|
|
from openhands.llm import bedrock
|
|
|
-from openhands.runtime.base import Runtime
|
|
|
+from openhands.runtime.base import Runtime, RuntimeUnavailableError
|
|
|
from openhands.server.auth.auth import get_sid_from_token, sign_token
|
|
|
from openhands.server.middleware import (
|
|
|
InMemoryRateLimiter,
|
|
|
@@ -517,7 +517,14 @@ async def list_files(request: Request, path: str | None = None):
|
|
|
)
|
|
|
|
|
|
runtime: Runtime = request.state.conversation.runtime
|
|
|
- file_list = await call_sync_from_async(runtime.list_files, path)
|
|
|
+ try:
|
|
|
+ file_list = await call_sync_from_async(runtime.list_files, path)
|
|
|
+ except RuntimeUnavailableError as e:
|
|
|
+ logger.error(f'Error listing files: {e}', exc_info=True)
|
|
|
+ return JSONResponse(
|
|
|
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
|
+ content={'error': f'Error listing files: {e}'},
|
|
|
+ )
|
|
|
if path:
|
|
|
file_list = [os.path.join(path, f) for f in file_list]
|
|
|
|
|
|
@@ -537,7 +544,14 @@ async def list_files(request: Request, path: str | None = None):
|
|
|
file_list = [entry for entry in file_list if not spec.match_file(entry)]
|
|
|
return file_list
|
|
|
|
|
|
- file_list = await filter_for_gitignore(file_list, '')
|
|
|
+ try:
|
|
|
+ file_list = await filter_for_gitignore(file_list, '')
|
|
|
+ except RuntimeUnavailableError as e:
|
|
|
+ logger.error(f'Error filtering files: {e}', exc_info=True)
|
|
|
+ return JSONResponse(
|
|
|
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
|
+ content={'error': f'Error filtering files: {e}'},
|
|
|
+ )
|
|
|
|
|
|
return file_list
|
|
|
|
|
|
@@ -566,7 +580,14 @@ async def select_file(file: str, request: Request):
|
|
|
|
|
|
file = os.path.join(runtime.config.workspace_mount_path_in_sandbox, file)
|
|
|
read_action = FileReadAction(file)
|
|
|
- observation = await call_sync_from_async(runtime.run_action, read_action)
|
|
|
+ try:
|
|
|
+ observation = await call_sync_from_async(runtime.run_action, read_action)
|
|
|
+ except RuntimeUnavailableError as e:
|
|
|
+ logger.error(f'Error opening file {file}: {e}', exc_info=True)
|
|
|
+ return JSONResponse(
|
|
|
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
|
+ content={'error': f'Error opening file: {e}'},
|
|
|
+ )
|
|
|
|
|
|
if isinstance(observation, FileReadObservation):
|
|
|
content = observation.content
|
|
|
@@ -662,9 +683,20 @@ async def upload_file(request: Request, files: list[UploadFile]):
|
|
|
tmp_file.flush()
|
|
|
|
|
|
runtime: Runtime = request.state.conversation.runtime
|
|
|
- runtime.copy_to(
|
|
|
- tmp_file_path, runtime.config.workspace_mount_path_in_sandbox
|
|
|
- )
|
|
|
+ try:
|
|
|
+ await call_sync_from_async(
|
|
|
+ runtime.copy_to,
|
|
|
+ tmp_file_path,
|
|
|
+ runtime.config.workspace_mount_path_in_sandbox,
|
|
|
+ )
|
|
|
+ except RuntimeUnavailableError as e:
|
|
|
+ logger.error(
|
|
|
+ f'Error saving file {safe_filename}: {e}', exc_info=True
|
|
|
+ )
|
|
|
+ return JSONResponse(
|
|
|
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
|
+ content={'error': f'Error saving file: {e}'},
|
|
|
+ )
|
|
|
uploaded_files.append(safe_filename)
|
|
|
|
|
|
response_content = {
|
|
|
@@ -795,7 +827,14 @@ async def save_file(request: Request):
|
|
|
runtime.config.workspace_mount_path_in_sandbox, file_path
|
|
|
)
|
|
|
write_action = FileWriteAction(file_path, content)
|
|
|
- observation = await call_sync_from_async(runtime.run_action, write_action)
|
|
|
+ try:
|
|
|
+ observation = await call_sync_from_async(runtime.run_action, write_action)
|
|
|
+ except RuntimeUnavailableError as e:
|
|
|
+ logger.error(f'Error saving file: {e}', exc_info=True)
|
|
|
+ return JSONResponse(
|
|
|
+ status_code=500,
|
|
|
+ content={'error': f'Error saving file: {e}'},
|
|
|
+ )
|
|
|
|
|
|
if isinstance(observation, FileWriteObservation):
|
|
|
return JSONResponse(
|
|
|
@@ -846,7 +885,14 @@ async def zip_current_workspace(request: Request, background_tasks: BackgroundTa
|
|
|
logger.debug('Zipping workspace')
|
|
|
runtime: Runtime = request.state.conversation.runtime
|
|
|
path = runtime.config.workspace_mount_path_in_sandbox
|
|
|
- zip_file = await call_sync_from_async(runtime.copy_from, path)
|
|
|
+ try:
|
|
|
+ zip_file = await call_sync_from_async(runtime.copy_from, path)
|
|
|
+ except RuntimeUnavailableError as e:
|
|
|
+ logger.error(f'Error zipping workspace: {e}', exc_info=True)
|
|
|
+ return JSONResponse(
|
|
|
+ status_code=500,
|
|
|
+ content={'error': f'Error zipping workspace: {e}'},
|
|
|
+ )
|
|
|
response = FileResponse(
|
|
|
path=zip_file,
|
|
|
filename='workspace.zip',
|