feat: add argument --base-container-image to resolver (#7612)

Co-authored-by: Xingyao Wang <xingyao@all-hands.dev>
This commit is contained in:
Tetsuuuuuuu 2025-04-21 23:01:03 +09:00 committed by GitHub
parent a792f84a83
commit 50426edaa1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 67 additions and 7 deletions

View File

@ -46,7 +46,7 @@ class SandboxConfig(BaseModel):
pause_closed_runtimes: bool = Field(default=True)
rm_all_containers: bool = Field(default=False)
api_key: str | None = Field(default=None)
base_container_image: str = Field(
base_container_image: str | None = Field(
default='nikolaik/python-nodejs:python3.12-nodejs22'
)
runtime_container_image: str | None = Field(default=None)

View File

@ -11,6 +11,7 @@ from typing import Any, Awaitable, TextIO
from pydantic import SecretStr
from tqdm import tqdm
import openhands
from openhands.core.config import LLMConfig
from openhands.core.logger import openhands_logger as logger
from openhands.integrations.service_types import ProviderType
@ -59,6 +60,7 @@ async def resolve_issues(
num_workers: int,
output_dir: str,
llm_config: LLMConfig,
base_container_image: str | None,
runtime_container_image: str,
prompt_template: str,
issue_type: str,
@ -199,6 +201,7 @@ async def resolve_issues(
max_iterations,
llm_config,
output_dir,
base_container_image,
runtime_container_image,
prompt_template,
issue_handler,
@ -249,6 +252,12 @@ def main() -> None:
default=None,
help='Github or Gitlab username to access the repository.',
)
parser.add_argument(
'--base-container-image',
type=str,
default=None,
help='Base container image to use.',
)
parser.add_argument(
'--runtime-container-image',
type=str,
@ -331,9 +340,21 @@ def main() -> None:
my_args = parser.parse_args()
base_container_image = my_args.base_container_image
runtime_container_image = my_args.runtime_container_image
if runtime_container_image is None:
runtime_container_image = 'ghcr.io/all-hands-ai/runtime:0.33.0-nikolaik'
if runtime_container_image is not None and base_container_image is not None:
raise ValueError('Cannot provide both runtime and base container images.')
if (
runtime_container_image is None
and base_container_image is None
and not my_args.is_experimental
):
runtime_container_image = (
f'ghcr.io/all-hands-ai/runtime:{openhands.__version__}-nikolaik'
)
owner, repo = my_args.selected_repo.split('/')
token = my_args.token or os.getenv('GITHUB_TOKEN') or os.getenv('GITLAB_TOKEN')
@ -386,6 +407,7 @@ def main() -> None:
token=token,
username=username,
platform=platform,
base_container_image=base_container_image,
runtime_container_image=runtime_container_image,
max_iterations=my_args.max_iterations,
limit_issues=my_args.limit_issues,

View File

@ -167,6 +167,7 @@ async def process_issue(
max_iterations: int,
llm_config: LLMConfig,
output_dir: str,
base_container_image: str | None,
runtime_container_image: str | None,
prompt_template: str,
issue_handler: ServiceContextIssue | ServiceContextPR,
@ -195,6 +196,7 @@ async def process_issue(
# they're set by default if nothing else overrides them
# FIXME we should remove them here
sandbox_config = SandboxConfig(
base_container_image=base_container_image,
runtime_container_image=runtime_container_image,
enable_auto_lint=False,
use_host_network=False,
@ -360,6 +362,7 @@ async def resolve_issue(
max_iterations: int,
output_dir: str,
llm_config: LLMConfig,
base_container_image: str | None,
runtime_container_image: str | None,
prompt_template: str,
issue_type: str,
@ -525,6 +528,7 @@ async def resolve_issue(
max_iterations,
llm_config,
output_dir,
base_container_image,
runtime_container_image,
prompt_template,
issue_handler,
@ -567,6 +571,12 @@ def main() -> None:
default=None,
help='username to access the repository.',
)
parser.add_argument(
'--base-container-image',
type=str,
default=None,
help='base container image to use.',
)
parser.add_argument(
'--runtime-container-image',
type=str,
@ -649,8 +659,18 @@ def main() -> None:
my_args = parser.parse_args()
base_container_image = my_args.base_container_image
runtime_container_image = my_args.runtime_container_image
if runtime_container_image is None and not my_args.is_experimental:
if runtime_container_image is not None and base_container_image is not None:
raise ValueError('Cannot provide both runtime and base container images.')
if (
runtime_container_image is None
and base_container_image is None
and not my_args.is_experimental
):
runtime_container_image = (
f'ghcr.io/all-hands-ai/runtime:{openhands.__version__}-nikolaik'
)
@ -714,6 +734,7 @@ def main() -> None:
token=token,
username=username,
platform=platform,
base_container_image=base_container_image,
runtime_container_image=runtime_container_image,
max_iterations=my_args.max_iterations,
output_dir=my_args.output_dir,

View File

@ -159,6 +159,14 @@ class DockerRuntimeBuilder(RuntimeBuilder):
f'================ {buildx_cmd[0].upper()} BUILD STARTED ================'
)
builder_cmd = ['docker', 'buildx', 'use', 'default']
subprocess.Popen(
builder_cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=True,
)
try:
process = subprocess.Popen(
buildx_cmd,

View File

@ -194,7 +194,10 @@ class RemoteRuntime(ActionExecutionClient):
'debug',
f'Runtime image repo: {os.environ["OH_RUNTIME_RUNTIME_IMAGE_REPO"]}',
)
if self.config.sandbox.base_container_image is None:
raise ValueError(
'base_container_image is required to build the runtime image. '
)
if self.config.sandbox.runtime_extra_deps:
self.log(
'debug',

4
poetry.lock generated
View File

@ -2663,7 +2663,7 @@ grpcio = {version = ">=1.49.1,<2.0dev", optional = true, markers = "python_versi
grpcio-status = {version = ">=1.49.1,<2.0.dev0", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""}
proto-plus = [
{version = ">=1.25.0,<2.0.0dev", markers = "python_version >= \"3.13\""},
{version = ">=1.22.3,<2.0.0dev", markers = "python_version < \"3.13\""},
{version = ">=1.22.3,<2.0.0dev"},
]
protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0.dev0"
requests = ">=2.18.0,<3.0.0.dev0"
@ -2877,7 +2877,7 @@ google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0dev"
grpc-google-iam-v1 = ">=0.14.0,<1.0.0dev"
proto-plus = [
{version = ">=1.25.0,<2.0.0dev", markers = "python_version >= \"3.13\""},
{version = ">=1.22.3,<2.0.0dev"},
{version = ">=1.22.3,<2.0.0dev", markers = "python_version < \"3.13\""},
]
protobuf = ">=3.20.2,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0dev"

View File

@ -112,6 +112,7 @@ async def test_resolve_issue_no_issues_found():
max_iterations=5,
output_dir='/tmp',
llm_config=LLMConfig(model='test', api_key='test'),
base_container_image='test-image',
runtime_container_image='test-image',
prompt_template='test-template',
issue_type='pr',
@ -344,6 +345,7 @@ async def test_process_issue(mock_output_dir, mock_prompt_template):
repo_instruction = 'Resolve this repo'
max_iterations = 5
llm_config = LLMConfig(model='test_model', api_key='test_api_key')
base_container_image = 'test_image:latest'
runtime_container_image = 'test_image:latest'
# Test cases for different scenarios
@ -449,6 +451,7 @@ async def test_process_issue(mock_output_dir, mock_prompt_template):
max_iterations,
llm_config,
mock_output_dir,
base_container_image,
runtime_container_image,
mock_prompt_template,
handler_instance,

View File

@ -132,6 +132,7 @@ async def test_resolve_issue_no_issues_found():
max_iterations=5,
output_dir='/tmp',
llm_config=LLMConfig(model='test', api_key='test'),
base_container_image='test-image',
runtime_container_image='test-image',
prompt_template='test-template',
issue_type='pr',
@ -384,6 +385,7 @@ async def test_process_issue(mock_output_dir, mock_prompt_template):
repo_instruction = 'Resolve this repo'
max_iterations = 5
llm_config = LLMConfig(model='test_model', api_key='test_api_key')
base_container_image = 'test_image:latest'
runtime_container_image = 'test_image:latest'
# Test cases for different scenarios
@ -489,6 +491,7 @@ async def test_process_issue(mock_output_dir, mock_prompt_template):
max_iterations,
llm_config,
mock_output_dir,
base_container_image,
runtime_container_image,
mock_prompt_template,
handler_instance,