Skip to content

Commit

Permalink
Merge branch 'OpenDevin:main' into kevin
Browse files Browse the repository at this point in the history
  • Loading branch information
SmartManoj authored Aug 1, 2024
2 parents a9281f2 + 21ea995 commit e1a21a3
Show file tree
Hide file tree
Showing 25 changed files with 319 additions and 177 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/dummy-agent-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
- name: Set up environment
run: |
curl -sSL https://install.python-poetry.org | python3 -
poetry install --without evaluation
poetry install --without evaluation,llama-index
poetry run playwright install --with-deps chromium
wget https://huggingface.co/BAAI/bge-small-en-v1.5/raw/main/1_Pooling/config.json -P /tmp/llama_index/models--BAAI--bge-small-en-v1.5/snapshots/5c38ec7c405ec4b44b94cc5a9bb96e735b38267a/1_Pooling/
- name: Run tests
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/review-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ jobs:
run: |
curl -sSL https://install.python-poetry.org | python3 -
export PATH="/github/home/.local/bin:$PATH"
poetry install --without evaluation
poetry install --without evaluation,llama-index
poetry run playwright install --with-deps chromium
- name: Run OpenDevin
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/run-unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ jobs:
cache: "poetry"

- name: Install Python dependencies using Poetry
run: poetry install
run: poetry install --without evaluation,llama-index

- name: Install & Start Docker
if: env.INSTALL_DOCKER == '1'
Expand Down Expand Up @@ -153,7 +153,7 @@ jobs:
cache: "poetry"

- name: Install Python dependencies using Poetry
run: poetry install --without evaluation
run: poetry install --without evaluation,llama-index

- name: Build Environment
run: make build
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/solve-issue.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
run: |
curl -sSL https://install.python-poetry.org | python3 -
export PATH="/github/home/.local/bin:$PATH"
poetry install --without evaluation
poetry install --without evaluation,llama-index
poetry run playwright install --with-deps chromium
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ install-python-dependencies:
export HNSWLIB_NO_NATIVE=1; \
poetry run pip install chroma-hnswlib; \
fi
@poetry install
@poetry install --without llama-index
@if [ -f "/etc/manjaro-release" ]; then \
echo "$(BLUE)Detected Manjaro Linux. Installing Playwright dependencies...$(RESET)"; \
poetry run pip install playwright; \
Expand Down
2 changes: 1 addition & 1 deletion containers/app/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ RUN apt-get update -y \

COPY ./pyproject.toml ./poetry.lock ./
RUN touch README.md
RUN export POETRY_CACHE_DIR && poetry install --without evaluation --no-root && rm -rf $POETRY_CACHE_DIR
RUN export POETRY_CACHE_DIR && poetry install --without evaluation,llama-index --no-root && rm -rf $POETRY_CACHE_DIR

FROM python:3.12.3-slim AS runtime

Expand Down
27 changes: 21 additions & 6 deletions docs/modules/usage/custom_sandbox_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,35 @@ sidebar_position: 6

# 💿 How to Create and Use a Custom Docker Sandbox

The default OpenDevin sandbox comes with a [minimal ubuntu configuration](https://github.com/OpenDevin/OpenDevin/blob/main/containers/sandbox/Dockerfile).
The default OpenDevin sandbox comes with a [minimal ubuntu configuration](https://github.com/OpenDevin/OpenDevin/blob/main/containers/sandbox/Dockerfile).

Your use case may need additional software installed by default.

There are two ways you can do so:

1. Use an existing image from docker hub. For instance, if you want to have `nodejs` installed, you can do so by using the `node:20` image
2. Creating your own custom docker image and using it

If you want to take the first approach, you can skip the `Create Your Docker Image` section.

For a more feature-rich environment, you might consider using pre-built images like **[nikolaik/python-nodejs](https://hub.docker.com/r/nikolaik/python-nodejs)**, which comes with both Python and Node.js pre-installed, along with many other useful tools and libraries, like:

- Node.js: 22.x
- npm: 10.x
- yarn: stable
- Python: latest
- pip: latest
- pipenv: latest
- poetry: latest
- uv: latest

## Setup

Make sure you are able to run OpenDevin using the [Development.md](https://github.com/OpenDevin/OpenDevin/blob/main/Development.md) first.

## Create Your Docker Image
To create a custom docker image, it must be debian/ubuntu based.

To create a custom docker image, it must be debian/ubuntu based.

For example, if we want OpenDevin to have access to the `node` binary, we would use the following Dockerfile:

Expand All @@ -34,7 +47,7 @@ RUN apt-get update && apt-get install -y
RUN apt-get install -y nodejs
```

Next build your docker image with the name of your choice, for example `custom_image`.
Next build your docker image with the name of your choice, for example `custom_image`.

To do this you can create a directory and put your file inside it with the name `Dockerfile`, and inside the directory run the following command:

Expand All @@ -50,7 +63,7 @@ This will produce a new image called ```custom_image``` that will be available i
## Specify your sandbox image in config.toml file

OpenDevin configuration occurs via the top-level `config.toml` file.
OpenDevin configuration occurs via the top-level `config.toml` file.

Create a `config.toml` file in the OpenDevin directory and enter these contents:

Expand All @@ -63,6 +76,7 @@ sandbox_container_image="custom_image"
```

For `sandbox_container_image`, you can specify either:

1. The name of your custom image that you built in the previous step (e.g., `”custom_image”`)
2. A pre-existing image from Docker Hub (e.g., `”node:20”` if you want a sandbox with Node.js pre-installed)

Expand All @@ -79,7 +93,7 @@ Congratulations!

The relevant code is defined in [ssh_box.py](https://github.com/OpenDevin/OpenDevin/blob/main/opendevin/runtime/docker/ssh_box.py) and [image_agnostic_util.py](https://github.com/OpenDevin/OpenDevin/blob/main/opendevin/runtime/docker/image_agnostic_util.py).

In particular, ssh_box.py checks the config object for ```config.sandbox_container_image``` and then attempts to retrieve the image using [get_od_sandbox_image](https://github.com/OpenDevin/OpenDevin/blob/main/opendevin/runtime/docker/image_agnostic_util.py#L72) which is defined in image_agnostic_util.py.
In particular, `ssh_box.py` checks the config object for ```config.sandbox_container_image``` and then attempts to retrieve the image using [get_od_sandbox_image](https://github.com/OpenDevin/OpenDevin/blob/main/opendevin/runtime/docker/image_agnostic_util.py#L72) which is defined in image_agnostic_util.py.

When first using a custom image, it will not be found and thus it will be built (on subsequent runs the built image will be found and returned).

Expand Down Expand Up @@ -109,6 +123,7 @@ dockerfile_content = (
## Troubleshooting / Errors

### Error: ```useradd: UID 1000 is not unique```

If you see this error in the console output it is because OpenDevin is trying to create the opendevin user in the sandbox with a UID of 1000, however this UID is already being used in the image (for some reason). To fix this change the sandbox_user_id field in the config.toml file to a different value:

```toml
Expand All @@ -122,7 +137,7 @@ sandbox_user_id="1001"

### Port use errors

If you see an error about a port being in use or unavailable, try deleting all running Docker Containers (run `docker ps` and `docker rm` relevant containers) and then re-running ```make run```
If you see an error about a port being in use or unavailable, try deleting all running Docker Containers (run `docker ps` and `docker rm` relevant containers) and then re-running ```make run``` .

## Discuss

Expand Down
9 changes: 8 additions & 1 deletion evaluation/miniwob/run_infer.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,14 @@
def get_sandbox():
global docker_ssh_box
if docker_ssh_box is None:
docker_ssh_box = DockerSSHBox()
docker_ssh_box = DockerSSHBox(
config=config.sandbox,
persist_sandbox=False,
workspace_mount_path=config.workspace_mount_path,
sandbox_workspace_dir=config.workspace_mount_path_in_sandbox,
cache_dir=config.cache_dir,
run_as_devin=config.run_as_devin,
)
return docker_ssh_box


Expand Down
1 change: 1 addition & 0 deletions evaluation/swe_bench/run_infer.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ def process_instance(
# You can omit this if you don't need to setup specialized sandbox
workspace_dir_name = f'{instance.repo}__{instance.version}'.replace('/', '__')
sandbox = SWEBenchSSHBox.get_box_for_instance(
config,
instance,
workspace_dir_name,
workspace_mount_path=workspace_mount_path,
Expand Down
2 changes: 1 addition & 1 deletion evaluation/swe_bench/swe_env_box.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,8 @@ def volumes(self):
@classmethod
def get_box_for_instance(
cls,
instance,
config: AppConfig,
instance,
workspace_dir_name=None,
skip_workspace_mount: bool = True,
workspace_mount_path: str | None = None,
Expand Down
15 changes: 8 additions & 7 deletions frontend/src/components/modals/settings/SettingsForm.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ describe("SettingsForm", () => {
expect(confirmationModeInput).toHaveAttribute("data-selected", "true");
});

it("should display the existing values if it they are present", () => {
it("should display the existing values if they are present", () => {
renderSettingsForm({
LLM_MODEL: "model2",
AGENT: "agent2",
Expand Down Expand Up @@ -119,17 +119,18 @@ describe("SettingsForm", () => {
});

it("should call the onAgentChange handler when the agent changes", async () => {
const user = userEvent.setup();
renderSettingsForm();

// We need to enable the agent select
const agentSwitch = screen.getByTestId("enableagentselect");
await user.click(agentSwitch);

const agentInput = screen.getByRole("combobox", { name: "agent" });
await act(async () => {
await userEvent.click(agentInput);
});
await user.click(agentInput);

const agent3 = screen.getByText("agent3");
await act(async () => {
await userEvent.click(agent3);
});
await user.click(agent3);

expect(onAgentChangeMock).toHaveBeenCalledWith("agent3");
});
Expand Down
26 changes: 18 additions & 8 deletions frontend/src/components/modals/settings/SettingsForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,10 @@ function SettingsForm({
}: SettingsFormProps) {
const { t } = useTranslation();
const { isOpen: isVisible, onOpenChange: onVisibleChange } = useDisclosure();
const [isAgentSelectEnabled, setIsAgentSelectEnabled] = React.useState(false);

return (
<>
<AutocompleteCombobox
ariaLabel="agent"
items={agents.map((agent) => ({ value: agent, label: agent }))}
defaultKey={settings.AGENT}
onChange={onAgentChange}
tooltip={t(I18nKey.SETTINGS$AGENT_TOOLTIP)}
disabled={disabled}
/>
<AutocompleteCombobox
ariaLabel="model"
items={models.map((model) => ({ value: model, label: model }))}
Expand Down Expand Up @@ -88,6 +81,23 @@ function SettingsForm({
tooltip={t(I18nKey.SETTINGS$LANGUAGE_TOOLTIP)}
disabled={disabled}
/>
<AutocompleteCombobox
ariaLabel="agent"
items={agents.map((agent) => ({ value: agent, label: agent }))}
defaultKey={settings.AGENT}
onChange={onAgentChange}
tooltip={t(I18nKey.SETTINGS$AGENT_TOOLTIP)}
disabled={disabled || !isAgentSelectEnabled}
/>
<Switch
defaultSelected={false}
isSelected={isAgentSelectEnabled}
onValueChange={setIsAgentSelectEnabled}
aria-label="enableagentselect"
data-testid="enableagentselect"
>
{t(I18nKey.SETTINGS$AGENT_SELECT_ENABLED)}
</Switch>
<Switch
aria-label="confirmationmode"
data-testid="confirmationmode"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,10 @@ describe("SettingsModal", () => {
),
);

// We need to enable the agent select first
const agentSwitch = screen.getByTestId("enableagentselect");
await user.click(agentSwitch);

const resetButton = screen.getByRole("button", {
name: /MODAL_RESET_BUTTON_LABEL/i,
});
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/i18n/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,9 @@
"de": "Wartet auf die Bestätigung des Benutzers, bevor der Code ausgeführt wird.",
"zh-CN": "在执行代码之前等待用户确认。"
},
"SETTINGS$AGENT_SELECT_ENABLED": {
"en": "Enable Agent Selection - Advanced Users"
},
"BROWSER$EMPTY_MESSAGE": {
"en": "No page loaded.",
"zh-CN": "页面未加载",
Expand Down
4 changes: 2 additions & 2 deletions opendevin/events/observation/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from .error import ErrorObservation
from .files import FileReadObservation, FileWriteObservation
from .observation import Observation
from .reject import RejectObservation
from .reject import UserRejectObservation
from .success import SuccessObservation

__all__ = [
Expand All @@ -21,5 +21,5 @@
'AgentStateChangedObservation',
'AgentDelegateObservation',
'SuccessObservation',
'RejectObservation',
'UserRejectObservation',
]
2 changes: 1 addition & 1 deletion opendevin/events/observation/reject.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@


@dataclass
class RejectObservation(Observation):
class UserRejectObservation(Observation):
"""This data class represents the result of a successful action."""

observation: str = ObservationType.USER_REJECTED
Expand Down
4 changes: 2 additions & 2 deletions opendevin/events/serialization/observation.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from opendevin.events.observation.error import ErrorObservation
from opendevin.events.observation.files import FileReadObservation, FileWriteObservation
from opendevin.events.observation.observation import Observation
from opendevin.events.observation.reject import RejectObservation
from opendevin.events.observation.reject import UserRejectObservation
from opendevin.events.observation.success import SuccessObservation

observations = (
Expand All @@ -23,7 +23,7 @@
SuccessObservation,
ErrorObservation,
AgentStateChangedObservation,
RejectObservation,
UserRejectObservation,
)

OBSERVATION_TYPE_TO_CLASS = {
Expand Down
Loading

0 comments on commit e1a21a3

Please sign in to comment.