Skip to content

Commit

Permalink
Merge branch 'All-Hands-AI:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
RainRat authored Mar 2, 2025
2 parents d63528e + 85c0864 commit a919512
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 20 deletions.
13 changes: 10 additions & 3 deletions ISSUE_TRIAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
These are the procedures and guidelines on how issues are triaged in this repo by the maintainers.

## General
* Most issues must be tagged with **enhancement** or **bug**.
* Issues may be tagged with what it relates to (**backend**, **frontend**, **agent quality**, etc.).
* All issues must be tagged with **enhancement**, **bug** or **troubleshooting/help**.
* Issues may be tagged with what it relates to (**agent quality**, **frontend**, **resolver**, etc.).

## Severity
* **Low**: Minor issues or affecting single user.
* **Medium**: Affecting multiple users.
* **High**: High visibility issues or affecting many users.
* **Critical**: Affecting all users or potential security issues.

## Effort
Expand All @@ -18,8 +19,14 @@ These are the procedures and guidelines on how issues are triaged in this repo b

## Not Enough Information
* User is asked to provide more information (logs, how to reproduce, etc.) when the issue is not clear.
* If an issue is unclear and the author does not provide more information or respond to a request, the issue may be closed as **not planned** (Usually after a week).
* If an issue is unclear and the author does not provide more information or respond to a request,
the issue may be closed as **not planned** (Usually after a week).

## Multiple Requests/Fixes in One Issue
* These issues will be narrowed down to one request/fix so the issue is more easily tracked and fixed.
* Issues may be broken down into multiple issues if required.

## Stale and Auto Closures
* In order to keep a maintainable backlog, issues that have no activity within 30 days are automatically marked as **Stale**.
* If issues marked as **Stale** continue to have no activity for 7 more days, they will automatically be closed as not planned.
* Issues may be reopened by maintainers if deemed important.
2 changes: 1 addition & 1 deletion evaluation/benchmarks/swe_bench/eval_infer.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ def process_instance(
'model_patch': model_patch,
'instance_id': instance_id,
},
log_path=test_output_path,
test_log_path=test_output_path,
include_tests_status=True,
)
report = _report[instance_id]
Expand Down
26 changes: 19 additions & 7 deletions openhands/runtime/builder/docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,25 @@ def __init__(self, docker_client: docker.DockerClient):

version_info = self.docker_client.version()
server_version = version_info.get('Version', '').replace('-', '.')
if tuple(map(int, server_version.split('.')[:2])) < (18, 9):
self.is_podman = version_info.get('Components')[0].get('Name').startswith('Podman')
if tuple(map(int, server_version.split('.')[:2])) < (18, 9) and not self.is_podman:
raise AgentRuntimeBuildError(
'Docker server version must be >= 18.09 to use BuildKit'
)

if self.is_podman and tuple(map(int, server_version.split('.')[:2])) < (4, 9):
raise AgentRuntimeBuildError(
'Podman server version must be >= 4.9.0'
)

self.rolling_logger = RollingLogger(max_lines=10)

@staticmethod
def check_buildx():
def check_buildx(is_podman: bool = False):
"""Check if Docker Buildx is available"""
try:
result = subprocess.run(
['docker', 'buildx', 'version'], capture_output=True, text=True
['docker' if not is_podman else 'podman', 'buildx', 'version'], capture_output=True, text=True
)
return result.returncode == 0
except FileNotFoundError:
Expand Down Expand Up @@ -68,12 +74,18 @@ def build(
self.docker_client = docker.from_env()
version_info = self.docker_client.version()
server_version = version_info.get('Version', '').split('+')[0].replace('-', '.')
if tuple(map(int, server_version.split('.'))) < (18, 9):
self.is_podman = version_info.get('Components')[0].get('Name').startswith('Podman')
if tuple(map(int, server_version.split('.'))) < (18, 9) and not self.is_podman:
raise AgentRuntimeBuildError(
'Docker server version must be >= 18.09 to use BuildKit'
)

if not DockerRuntimeBuilder.check_buildx():
if self.is_podman and tuple(map(int, server_version.split('.'))) < (4, 9):
raise AgentRuntimeBuildError(
'Podman server version must be >= 4.9.0'
)

if not DockerRuntimeBuilder.check_buildx(self.is_podman):
# when running openhands in a container, there might not be a "docker"
# binary available, in which case we need to download docker binary.
# since the official openhands app image is built from debian, we use
Expand Down Expand Up @@ -110,7 +122,7 @@ def build(
target_image_tag = tags[1].split(':')[1] if len(tags) > 1 else None

buildx_cmd = [
'docker',
'docker' if not self.is_podman else 'podman',
'buildx',
'build',
'--progress=plain',
Expand Down Expand Up @@ -139,7 +151,7 @@ def build(
buildx_cmd.append(path) # must be last!

self.rolling_logger.start(
'================ DOCKER BUILD STARTED ================'
f'================ {buildx_cmd[0].upper()} BUILD STARTED ================'
)

try:
Expand Down
42 changes: 37 additions & 5 deletions openhands/runtime/impl/daytona/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,54 @@

[Daytona](https://www.daytona.io/) is a platform that provides a secure and elastic infrastructure for running AI-generated code. It provides all the necessary features for an AI Agent to interact with a codebase. It provides a Daytona SDK with official Python and TypeScript interfaces for interacting with Daytona, enabling you to programmatically manage development environments and execute code.

## Quick start

Get your Daytona API key from https://app.daytona.io/dashboard/keys and export it:

```bash
export DAYTONA_API_KEY="<your-api-key>"
```

Use the following command to run the latest OpenHands release locally using Docker:

```bash
bash -i <(curl -sL https://get.daytona.io/openhands)
```


## Getting started

1. Sign in at https://app.daytona.io/

1. Generate and copy your API key

1. Set the following environment variables before running the OpenHands app on your local machine or via a `docker run` command:
1. Set the `OPENHANDS_VERSION` environment variable to the latest release's version seen in the main README.md file; as well as the `DAYTONA_API_KEY`

```bash
RUNTIME="daytona"
DAYTONA_API_KEY="<your-api-key>"
export OPENHANDS_VERSION=<OPENHANDS_RELEASE> # e.g. 0.27
export DAYTONA_API_KEY=<your_api_key>
```
Optionally, if you don't want your sandboxes to default to the US region, set:

1. Run the following `docker` command:

```bash
docker run -it --rm --pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:${OPENHANDS_VERSION}-nikolaik \
-e LOG_ALL_EVENTS=true \
-e RUNTIME=daytona \
-e DAYTONA_API_KEY=${DAYTONA_API_KEY} \
-v ~/.openhands-state:/.openhands-state \
-p 3000:3000 \
--name openhands-app \
docker.all-hands.dev/all-hands-ai/openhands:${OPENHANDS_VERSION}
```
> **Tip:** If you don't want your sandboxes to default to the US region, you can set the `DAYTONA_TARGET` environment variable to `eu`
Alternatively, if you want to run the OpenHands app on your local machine using `make run` without Docker, set the following environment variables first:

```bash
DAYTONA_TARGET="eu"
export RUNTIME="daytona"
export DAYTONA_API_KEY="<your-api-key>"
```

## Documentation
Expand Down
5 changes: 4 additions & 1 deletion tests/unit/test_docker_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ def mock_docker_client():
mock_client.return_value.containers.get.return_value = container_mock
mock_client.return_value.containers.run.return_value = container_mock
# Mock version info for BuildKit check
mock_client.return_value.version.return_value = {'Version': '20.10.0'}
mock_client.return_value.version.return_value = {
'Version': '20.10.0',
'Components': [{'Name': 'Engine', 'Version': '20.10.0'}],
} # Ensure version is >= 18.09
yield mock_client.return_value


Expand Down
13 changes: 10 additions & 3 deletions tests/unit/test_runtime_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ def temp_dir(tmp_path_factory: TempPathFactory) -> str:
def mock_docker_client():
mock_client = MagicMock(spec=docker.DockerClient)
mock_client.version.return_value = {
'Version': '19.03'
'Version': '20.10.0',
'Components': [{'Name': 'Engine', 'Version': '20.10.0'}],
} # Ensure version is >= 18.09
return mock_client

Expand Down Expand Up @@ -612,15 +613,21 @@ def test_build_image_from_repo(docker_runtime_builder, tmp_path):

def test_image_exists_local(docker_runtime_builder):
mock_client = MagicMock()
mock_client.version().get.return_value = '18.9'
mock_client.version.return_value = {
'Version': '20.10.0',
'Components': [{'Name': 'Engine', 'Version': '20.10.0'}],
} # Ensure version is >= 18.09
builder = DockerRuntimeBuilder(mock_client)
image_name = 'existing-local:image' # The mock pretends this exists by default
assert builder.image_exists(image_name)


def test_image_exists_not_found():
mock_client = MagicMock()
mock_client.version().get.return_value = '18.9'
mock_client.version.return_value = {
'Version': '20.10.0',
'Components': [{'Name': 'Engine', 'Version': '20.10.0'}],
} # Ensure version is >= 18.09
mock_client.images.get.side_effect = docker.errors.ImageNotFound(
"He doesn't like you!"
)
Expand Down

0 comments on commit a919512

Please sign in to comment.