From 4b303ec9b476bf83eca4d01955f08afe38721e43 Mon Sep 17 00:00:00 2001 From: Tim O'Farrell Date: Thu, 23 Oct 2025 14:43:45 -0600 Subject: [PATCH] Fixes to unblock frontend (#11488) Co-authored-by: Ray Myers --- .github/workflows/ghcr-build.yml | 2 +- Development.md | 2 +- containers/dev/compose.yml | 2 +- enterprise/Dockerfile | 2 +- enterprise/enterprise_local/README.md | 6 ++-- .../scripts/setup/prepare_swe_utils.sh | 2 +- .../scripts/setup/prepare_swe_utils.sh | 2 +- .../scripts/setup/prepare_swe_utils.sh | 2 +- .../the_agent_company/scripts/run_infer.sh | 2 +- .../app_conversation_service.py | 5 +++- .../git_app_conversation_service.py | 24 ++++++++------- .../live_status_app_conversation_service.py | 8 ++--- .../sandbox/docker_sandbox_service.py | 3 +- openhands/resolver/issue_resolver.py | 2 +- openhands/runtime/utils/runtime_build.py | 2 +- .../server/routes/manage_conversations.py | 30 +++++++++++-------- .../app_server/test_docker_sandbox_service.py | 2 +- tests/unit/resolver/test_resolve_issue.py | 4 +-- 18 files changed, 56 insertions(+), 46 deletions(-) diff --git a/.github/workflows/ghcr-build.yml b/.github/workflows/ghcr-build.yml index 78a193ce53..7675911076 100644 --- a/.github/workflows/ghcr-build.yml +++ b/.github/workflows/ghcr-build.yml @@ -46,7 +46,7 @@ jobs: else json=$(jq -n -c '[ { image: "nikolaik/python-nodejs:python3.12-nodejs22", tag: "nikolaik" }, - { image: "ghcr.io/all-hands-ai/python-nodejs:python3.13-nodejs22-trixie", tag: "trixie" }, + { image: "ghcr.io/openhands/python-nodejs:python3.13-nodejs22-trixie", tag: "trixie" }, { image: "ubuntu:24.04", tag: "ubuntu" } ]') fi diff --git a/Development.md b/Development.md index 0c78ed9330..98e7f827f9 100644 --- a/Development.md +++ b/Development.md @@ -159,7 +159,7 @@ poetry run pytest ./tests/unit/test_*.py To reduce build time (e.g., if no changes were made to the client-runtime component), you can use an existing Docker container image by setting the SANDBOX_RUNTIME_CONTAINER_IMAGE environment variable to the desired Docker image. -Example: `export SANDBOX_RUNTIME_CONTAINER_IMAGE=ghcr.io/all-hands-ai/runtime:0.59-nikolaik` +Example: `export SANDBOX_RUNTIME_CONTAINER_IMAGE=ghcr.io/openhands/runtime:0.59-nikolaik` ## Develop inside Docker container diff --git a/containers/dev/compose.yml b/containers/dev/compose.yml index e680edc4c9..0adcbd7a6a 100644 --- a/containers/dev/compose.yml +++ b/containers/dev/compose.yml @@ -12,7 +12,7 @@ services: - SANDBOX_API_HOSTNAME=host.docker.internal - DOCKER_HOST_ADDR=host.docker.internal # - - SANDBOX_RUNTIME_CONTAINER_IMAGE=${SANDBOX_RUNTIME_CONTAINER_IMAGE:-ghcr.io/all-hands-ai/runtime:0.59-nikolaik} + - SANDBOX_RUNTIME_CONTAINER_IMAGE=${SANDBOX_RUNTIME_CONTAINER_IMAGE:-ghcr.io/openhands/runtime:0.59-nikolaik} - SANDBOX_USER_ID=${SANDBOX_USER_ID:-1234} - WORKSPACE_MOUNT_PATH=${WORKSPACE_BASE:-$PWD/workspace} ports: diff --git a/enterprise/Dockerfile b/enterprise/Dockerfile index 65440cc2a4..b0ca56a7f6 100644 --- a/enterprise/Dockerfile +++ b/enterprise/Dockerfile @@ -1,5 +1,5 @@ ARG OPENHANDS_VERSION=latest -ARG BASE="ghcr.io/all-hands-ai/openhands" +ARG BASE="ghcr.io/openhands/openhands" FROM ${BASE}:${OPENHANDS_VERSION} # Datadog labels diff --git a/enterprise/enterprise_local/README.md b/enterprise/enterprise_local/README.md index e756e6cb7e..4d621f16a8 100644 --- a/enterprise/enterprise_local/README.md +++ b/enterprise/enterprise_local/README.md @@ -64,7 +64,7 @@ python enterprise_local/convert_to_env.py You'll also need to set up the runtime image, so that the dev server doesn't try to rebuild it. ``` -export SANDBOX_RUNTIME_CONTAINER_IMAGE=ghcr.io/all-hands-ai/runtime:main-nikolaik +export SANDBOX_RUNTIME_CONTAINER_IMAGE=ghcr.io/openhands/runtime:main-nikolaik docker pull $SANDBOX_RUNTIME_CONTAINER_IMAGE ``` @@ -203,7 +203,7 @@ And then invoking `printenv`. NOTE: _DO NOT DO THIS WITH PROD!!!_ (Hopefully by "REDIS_HOST": "localhost:6379", "OPENHANDS": "", "FRONTEND_DIRECTORY": "/frontend/build", - "SANDBOX_RUNTIME_CONTAINER_IMAGE": "ghcr.io/all-hands-ai/runtime:main-nikolaik", + "SANDBOX_RUNTIME_CONTAINER_IMAGE": "ghcr.io/openhands/runtime:main-nikolaik", "FILE_STORE_PATH": ">/.openhands-state", "OPENHANDS_CONFIG_CLS": "server.config.SaaSServerConfig", "GITHUB_APP_ID": "1062351", @@ -237,7 +237,7 @@ And then invoking `printenv`. NOTE: _DO NOT DO THIS WITH PROD!!!_ (Hopefully by "REDIS_HOST": "localhost:6379", "OPENHANDS": "", "FRONTEND_DIRECTORY": "/frontend/build", - "SANDBOX_RUNTIME_CONTAINER_IMAGE": "ghcr.io/all-hands-ai/runtime:main-nikolaik", + "SANDBOX_RUNTIME_CONTAINER_IMAGE": "ghcr.io/openhands/runtime:main-nikolaik", "FILE_STORE_PATH": ">/.openhands-state", "OPENHANDS_CONFIG_CLS": "server.config.SaaSServerConfig", "GITHUB_APP_ID": "1062351", diff --git a/evaluation/benchmarks/multi_swe_bench/scripts/setup/prepare_swe_utils.sh b/evaluation/benchmarks/multi_swe_bench/scripts/setup/prepare_swe_utils.sh index 7091b6f586..2d35c6f218 100644 --- a/evaluation/benchmarks/multi_swe_bench/scripts/setup/prepare_swe_utils.sh +++ b/evaluation/benchmarks/multi_swe_bench/scripts/setup/prepare_swe_utils.sh @@ -12,7 +12,7 @@ git clone -b $OH_SWE_BENCH_REPO_BRANCH $OH_SWE_BENCH_REPO_PATH $EVAL_WORKSPACE/O # 2. Prepare DATA echo "==== Prepare SWE-bench data ====" -EVAL_IMAGE=ghcr.io/all-hands-ai/eval-swe-bench:builder_with_conda +EVAL_IMAGE=ghcr.io/openhands/eval-swe-bench:builder_with_conda EVAL_WORKSPACE=$(realpath $EVAL_WORKSPACE) chmod +x $EVAL_WORKSPACE/OH-SWE-bench/swebench/harness/prepare_data.sh if [ -d $EVAL_WORKSPACE/eval_data ]; then diff --git a/evaluation/benchmarks/swe_bench/scripts/setup/prepare_swe_utils.sh b/evaluation/benchmarks/swe_bench/scripts/setup/prepare_swe_utils.sh index c5726a402f..f41c45e3f6 100755 --- a/evaluation/benchmarks/swe_bench/scripts/setup/prepare_swe_utils.sh +++ b/evaluation/benchmarks/swe_bench/scripts/setup/prepare_swe_utils.sh @@ -12,7 +12,7 @@ git clone -b $OH_SWE_BENCH_REPO_BRANCH $OH_SWE_BENCH_REPO_PATH $EVAL_WORKSPACE/O # 2. Prepare DATA echo "==== Prepare SWE-bench data ====" -EVAL_IMAGE=ghcr.io/all-hands-ai/eval-swe-bench:builder_with_conda +EVAL_IMAGE=ghcr.io/openhands/eval-swe-bench:builder_with_conda EVAL_WORKSPACE=$(realpath $EVAL_WORKSPACE) chmod +x $EVAL_WORKSPACE/OH-SWE-bench/swebench/harness/prepare_data.sh if [ -d $EVAL_WORKSPACE/eval_data ]; then diff --git a/evaluation/benchmarks/testgeneval/scripts/setup/prepare_swe_utils.sh b/evaluation/benchmarks/testgeneval/scripts/setup/prepare_swe_utils.sh index bc1f4c03b7..3b782a50c3 100755 --- a/evaluation/benchmarks/testgeneval/scripts/setup/prepare_swe_utils.sh +++ b/evaluation/benchmarks/testgeneval/scripts/setup/prepare_swe_utils.sh @@ -12,7 +12,7 @@ git clone -b $OH_SWE_BENCH_REPO_BRANCH $OH_SWE_BENCH_REPO_PATH $EVAL_WORKSPACE/O # 2. Prepare DATA echo "==== Prepare SWE-bench data ====" -EVAL_IMAGE=ghcr.io/all-hands-ai/eval-swe-bench:builder_with_conda +EVAL_IMAGE=ghcr.io/openhands/eval-swe-bench:builder_with_conda EVAL_WORKSPACE=$(realpath $EVAL_WORKSPACE) chmod +x $EVAL_WORKSPACE/OH-SWE-bench/swebench/harness/prepare_data.sh if [ -d $EVAL_WORKSPACE/eval_data ]; then diff --git a/evaluation/benchmarks/the_agent_company/scripts/run_infer.sh b/evaluation/benchmarks/the_agent_company/scripts/run_infer.sh index 14fbf4035f..2110e5ce48 100755 --- a/evaluation/benchmarks/the_agent_company/scripts/run_infer.sh +++ b/evaluation/benchmarks/the_agent_company/scripts/run_infer.sh @@ -162,7 +162,7 @@ while IFS= read -r task_image; do # Prune unused images and volumes docker image rm "$task_image" - docker images "ghcr.io/all-hands-ai/runtime" -q | xargs -r docker rmi -f + docker images "ghcr.io/openhands/runtime" -q | xargs -r docker rmi -f docker volume prune -f docker system prune -f done < "$temp_file" diff --git a/openhands/app_server/app_conversation/app_conversation_service.py b/openhands/app_server/app_conversation/app_conversation_service.py index a817d7e111..2cff627aeb 100644 --- a/openhands/app_server/app_conversation/app_conversation_service.py +++ b/openhands/app_server/app_conversation/app_conversation_service.py @@ -88,7 +88,10 @@ class AppConversationService(ABC): @abstractmethod async def run_setup_scripts( - self, task: AppConversationStartTask, workspace: Workspace + self, + task: AppConversationStartTask, + workspace: Workspace, + working_dir: str, ) -> AsyncGenerator[AppConversationStartTask, None]: """Run the setup scripts for the project and yield status updates""" yield task diff --git a/openhands/app_server/app_conversation/git_app_conversation_service.py b/openhands/app_server/app_conversation/git_app_conversation_service.py index cdbfda65e9..4ea9099163 100644 --- a/openhands/app_server/app_conversation/git_app_conversation_service.py +++ b/openhands/app_server/app_conversation/git_app_conversation_service.py @@ -36,23 +36,25 @@ class GitAppConversationService(AppConversationService, ABC): self, task: AppConversationStartTask, workspace: AsyncRemoteWorkspace, + working_dir: str, ) -> AsyncGenerator[AppConversationStartTask, None]: task.status = AppConversationStartTaskStatus.PREPARING_REPOSITORY yield task - await self.clone_or_init_git_repo(task, workspace) + await self.clone_or_init_git_repo(task, workspace, working_dir) task.status = AppConversationStartTaskStatus.RUNNING_SETUP_SCRIPT yield task - await self.maybe_run_setup_script(workspace) + await self.maybe_run_setup_script(workspace, working_dir) task.status = AppConversationStartTaskStatus.SETTING_UP_GIT_HOOKS yield task - await self.maybe_setup_git_hooks(workspace) + await self.maybe_setup_git_hooks(workspace, working_dir) async def clone_or_init_git_repo( self, task: AppConversationStartTask, workspace: AsyncRemoteWorkspace, + working_dir: str, ): request = task.request @@ -61,7 +63,7 @@ class GitAppConversationService(AppConversationService, ABC): _logger.debug('Initializing a new git repository in the workspace.') await workspace.execute_command( 'git init && git config --global --add safe.directory ' - + workspace.working_dir + + working_dir ) else: _logger.info('Not initializing a new git repository.') @@ -77,7 +79,7 @@ class GitAppConversationService(AppConversationService, ABC): # Clone the repo - this is the slow part! clone_command = f'git clone {remote_repo_url} {dir_name}' - await workspace.execute_command(clone_command, workspace.working_dir) + await workspace.execute_command(clone_command, working_dir) # Checkout the appropriate branch if request.selected_branch: @@ -87,14 +89,15 @@ class GitAppConversationService(AppConversationService, ABC): random_str = base62.encodebytes(os.urandom(16)) openhands_workspace_branch = f'openhands-workspace-{random_str}' checkout_command = f'git checkout -b {openhands_workspace_branch}' - await workspace.execute_command(checkout_command, workspace.working_dir) + await workspace.execute_command(checkout_command, working_dir) async def maybe_run_setup_script( self, workspace: AsyncRemoteWorkspace, + working_dir: str, ): """Run .openhands/setup.sh if it exists in the workspace or repository.""" - setup_script = workspace.working_dir + '/.openhands/setup.sh' + setup_script = working_dir + '/.openhands/setup.sh' await workspace.execute_command( f'chmod +x {setup_script} && source {setup_script}', timeout=600 @@ -108,10 +111,11 @@ class GitAppConversationService(AppConversationService, ABC): async def maybe_setup_git_hooks( self, workspace: AsyncRemoteWorkspace, + working_dir: str, ): """Set up git hooks if .openhands/pre-commit.sh exists in the workspace or repository.""" command = 'mkdir -p .git/hooks && chmod +x .openhands/pre-commit.sh' - result = await workspace.execute_command(command, workspace.working_dir) + result = await workspace.execute_command(command, working_dir) if result.exit_code: return @@ -127,9 +131,7 @@ class GitAppConversationService(AppConversationService, ABC): f'mv {PRE_COMMIT_HOOK} {PRE_COMMIT_LOCAL} &&' f'chmod +x {PRE_COMMIT_LOCAL}' ) - result = await workspace.execute_command( - command, workspace.working_dir - ) + result = await workspace.execute_command(command, working_dir) if result.exit_code != 0: _logger.error( f'Failed to preserve existing pre-commit hook: {result.stderr}', diff --git a/openhands/app_server/app_conversation/live_status_app_conversation_service.py b/openhands/app_server/app_conversation/live_status_app_conversation_service.py index 021550f327..3c8ee7203c 100644 --- a/openhands/app_server/app_conversation/live_status_app_conversation_service.py +++ b/openhands/app_server/app_conversation/live_status_app_conversation_service.py @@ -181,11 +181,11 @@ class LiveStatusAppConversationService(GitAppConversationService): # Run setup scripts workspace = AsyncRemoteWorkspace( - working_dir=sandbox_spec.working_dir, - server_url=agent_server_url, - session_api_key=sandbox.session_api_key, + host=agent_server_url, api_key=sandbox.session_api_key ) - async for updated_task in self.run_setup_scripts(task, workspace): + async for updated_task in self.run_setup_scripts( + task, workspace, sandbox_spec.working_dir + ): yield updated_task # Build the start request diff --git a/openhands/app_server/sandbox/docker_sandbox_service.py b/openhands/app_server/sandbox/docker_sandbox_service.py index e31a6ac222..0f6ea51916 100644 --- a/openhands/app_server/sandbox/docker_sandbox_service.py +++ b/openhands/app_server/sandbox/docker_sandbox_service.py @@ -90,7 +90,8 @@ class DockerSandboxService(SandboxService): status_mapping = { 'running': SandboxStatus.RUNNING, 'paused': SandboxStatus.PAUSED, - 'exited': SandboxStatus.MISSING, + # The stop button was pressed in the docker console + 'exited': SandboxStatus.PAUSED, 'created': SandboxStatus.STARTING, 'restarting': SandboxStatus.STARTING, 'removing': SandboxStatus.MISSING, diff --git a/openhands/resolver/issue_resolver.py b/openhands/resolver/issue_resolver.py index 8bec263782..143553818e 100644 --- a/openhands/resolver/issue_resolver.py +++ b/openhands/resolver/issue_resolver.py @@ -222,7 +222,7 @@ class IssueResolver: and not is_experimental ): runtime_container_image = ( - f'ghcr.io/all-hands-ai/runtime:{openhands.__version__}-nikolaik' + f'ghcr.io/openhands/runtime:{openhands.__version__}-nikolaik' ) # Convert container image values to string or None diff --git a/openhands/runtime/utils/runtime_build.py b/openhands/runtime/utils/runtime_build.py index 5c61fd0a3c..3b5281871a 100644 --- a/openhands/runtime/utils/runtime_build.py +++ b/openhands/runtime/utils/runtime_build.py @@ -25,7 +25,7 @@ class BuildFromImageType(Enum): def get_runtime_image_repo() -> str: - return os.getenv('OH_RUNTIME_RUNTIME_IMAGE_REPO', 'ghcr.io/all-hands-ai/runtime') + return os.getenv('OH_RUNTIME_RUNTIME_IMAGE_REPO', 'ghcr.io/openhands/runtime') def _generate_dockerfile( diff --git a/openhands/server/routes/manage_conversations.py b/openhands/server/routes/manage_conversations.py index 5bb2fcb6b6..2bf05e3c55 100644 --- a/openhands/server/routes/manage_conversations.py +++ b/openhands/server/routes/manage_conversations.py @@ -1139,25 +1139,29 @@ def _to_conversation_info(app_conversation: AppConversation) -> ConversationInfo app_conversation.sandbox_status, ConversationStatus.STOPPED ) - runtime_status_mapping = { - AgentExecutionStatus.ERROR: RuntimeStatus.ERROR, - AgentExecutionStatus.IDLE: RuntimeStatus.READY, - AgentExecutionStatus.RUNNING: RuntimeStatus.READY, - AgentExecutionStatus.PAUSED: RuntimeStatus.READY, - AgentExecutionStatus.WAITING_FOR_CONFIRMATION: RuntimeStatus.READY, - AgentExecutionStatus.FINISHED: RuntimeStatus.READY, - AgentExecutionStatus.STUCK: RuntimeStatus.ERROR, - } - runtime_status = runtime_status_mapping.get( - app_conversation.agent_status, RuntimeStatus.ERROR - ) + if conversation_status == ConversationStatus.RUNNING: + runtime_status_mapping = { + AgentExecutionStatus.ERROR: RuntimeStatus.ERROR, + AgentExecutionStatus.IDLE: RuntimeStatus.READY, + AgentExecutionStatus.RUNNING: RuntimeStatus.READY, + AgentExecutionStatus.PAUSED: RuntimeStatus.READY, + AgentExecutionStatus.WAITING_FOR_CONFIRMATION: RuntimeStatus.READY, + AgentExecutionStatus.FINISHED: RuntimeStatus.READY, + AgentExecutionStatus.STUCK: RuntimeStatus.ERROR, + } + runtime_status = runtime_status_mapping.get( + app_conversation.agent_status, RuntimeStatus.ERROR + ) + else: + runtime_status = None + title = ( app_conversation.title or f'Conversation {base62.encodebytes(app_conversation.id.bytes)}' ) return ConversationInfo( - conversation_id=str(app_conversation.id), + conversation_id=app_conversation.id.hex, title=title, last_updated_at=app_conversation.updated_at, status=conversation_status, diff --git a/tests/unit/app_server/test_docker_sandbox_service.py b/tests/unit/app_server/test_docker_sandbox_service.py index b3fc2fcd41..f79988773a 100644 --- a/tests/unit/app_server/test_docker_sandbox_service.py +++ b/tests/unit/app_server/test_docker_sandbox_service.py @@ -601,7 +601,7 @@ class TestDockerSandboxService: service._docker_status_to_sandbox_status('paused') == SandboxStatus.PAUSED ) assert ( - service._docker_status_to_sandbox_status('exited') == SandboxStatus.MISSING + service._docker_status_to_sandbox_status('exited') == SandboxStatus.PAUSED ) assert ( service._docker_status_to_sandbox_status('created') diff --git a/tests/unit/resolver/test_resolve_issue.py b/tests/unit/resolver/test_resolve_issue.py index b93830926e..e391913cbb 100644 --- a/tests/unit/resolver/test_resolve_issue.py +++ b/tests/unit/resolver/test_resolve_issue.py @@ -10,7 +10,7 @@ from openhands.resolver.issue_resolver import IssueResolver def assert_sandbox_config( config: SandboxConfig, base_container_image=SandboxConfig.model_fields['base_container_image'].default, - runtime_container_image='ghcr.io/all-hands-ai/runtime:mock-nikolaik', # Default to mock version + runtime_container_image='ghcr.io/openhands/runtime:mock-nikolaik', # Default to mock version local_runtime_url=SandboxConfig.model_fields['local_runtime_url'].default, enable_auto_lint=False, ): @@ -38,7 +38,7 @@ def test_setup_sandbox_config_default(): assert_sandbox_config( openhands_config.sandbox, - runtime_container_image='ghcr.io/all-hands-ai/runtime:mock-nikolaik', + runtime_container_image='ghcr.io/openhands/runtime:mock-nikolaik', )