Document various runtimes (#4536)

Co-authored-by: Xingyao Wang <xingyao@all-hands.dev>
This commit is contained in:
Robert Brennan 2024-10-30 12:18:42 -04:00 committed by GitHub
parent 3ae4bc0f8e
commit 2e50a5bef5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 2639 additions and 2372 deletions

View File

@ -1,5 +1,5 @@
# Workflow that builds, tests and then pushes the OpenHands and runtime docker images to the ghcr.io repository
name: Build, Test and Publish RT Image
name: Docker
# Always run on "main"
# Always run on tags

View File

@ -40,30 +40,28 @@ See the [Installation](https://docs.all-hands.dev/modules/usage/installation) gu
system requirements and more information.
```bash
export WORKSPACE_BASE=$(pwd)/workspace
docker pull docker.all-hands.dev/all-hands-ai/runtime:0.11-nikolaik
docker pull ghcr.io/all-hands-ai/runtime:0.11-nikolaik
docker run -it --pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=ghcr.io/all-hands-ai/runtime:0.11-nikolaik \
-e SANDBOX_USER_ID=$(id -u) \
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \
-v $WORKSPACE_BASE:/opt/workspace_base \
docker run -it --rm --pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.11-nikolaik \
-v /var/run/docker.sock:/var/run/docker.sock \
-p 3000:3000 \
--add-host host.docker.internal:host-gateway \
--name openhands-app-$(date +%Y%m%d%H%M%S) \
ghcr.io/all-hands-ai/openhands:0.11
--name openhands-app \
docker.all-hands.dev/all-hands-ai/openhands:0.11
```
You'll find OpenHands running at [http://localhost:3000](http://localhost:3000)!
You'll need a model provider and API key. One option that works well: [Claude 3.5 Sonnet](https://www.anthropic.com/api), but you have [many options](https://docs.all-hands.dev/modules/usage/llms).
You'll need a model provider and API key.
[Anthropic's Claude 3.5 Sonnet (`anthropic/claude-3-5-sonnet-20241022`)](https://www.anthropic.com/api)
works best, but you have [many options](https://docs.all-hands.dev/modules/usage/llms).
---
You can also run OpenHands in a scriptable [headless mode](https://docs.all-hands.dev/modules/usage/how-to/headless-mode),
or as an [interactive CLI](https://docs.all-hands.dev/modules/usage/how-to/cli-mode).
You can also [connect OpenHands to your local filesystem](https://docs.all-hands.dev/modules/usage/runtimes),
run OpenHands in a scriptable [headless mode](https://docs.all-hands.dev/modules/usage/how-to/headless-mode),
or interact with it via a [friendly CLI](https://docs.all-hands.dev/modules/usage/how-to/cli-mode).
Visit [Installation](https://docs.all-hands.dev/modules/usage/installation) for more information and setup instructions.

View File

@ -41,6 +41,7 @@ ENV SANDBOX_LOCAL_RUNTIME_URL=http://host.docker.internal
ENV USE_HOST_NETWORK=false
ENV WORKSPACE_BASE=/opt/workspace_base
ENV OPENHANDS_BUILD_VERSION=$OPENHANDS_BUILD_VERSION
ENV SANDBOX_USER_ID=0
RUN mkdir -p $WORKSPACE_BASE
RUN apt-get update -y \

View File

@ -18,6 +18,11 @@ if [ -z "$SANDBOX_USER_ID" ]; then
exit 1
fi
if [ -z "$WORKSPACE_MOUNT_PATH" ]; then
# This is set to /opt/workspace in the Dockerfile. But if the user isn't mounting, we want to unset it so that OpenHands doesn't mount at all
unset WORKSPACE_BASE
fi
if [[ "$SANDBOX_USER_ID" -eq 0 ]]; then
echo "Running OpenHands as root"
export RUN_AS_OPENHANDS=false

View File

@ -57,7 +57,7 @@ docker run -it \
-v /var/run/docker.sock:/var/run/docker.sock \
--add-host host.docker.internal:host-gateway \
--name openhands-app-$(date +%Y%m%d%H%M%S) \
ghcr.io/all-hands-ai/openhands:0.11 \
docker.all-hands.dev/all-hands-ai/openhands:0.11 \
python -m openhands.core.cli
```

View File

@ -51,6 +51,6 @@ docker run -it \
-v /var/run/docker.sock:/var/run/docker.sock \
--add-host host.docker.internal:host-gateway \
--name openhands-app-$(date +%Y%m%d%H%M%S) \
ghcr.io/all-hands-ai/openhands:0.11 \
docker.all-hands.dev/all-hands-ai/openhands:0.11 \
python -m openhands.core.main -t "write a bash script that prints hi"
```

View File

@ -150,7 +150,7 @@ metadata:
spec:
containers:
- name: openhands-app-2024
image: ghcr.io/all-hands-ai/openhands:main
image: docker.all-hands.dev/all-hands-ai/openhands:main
env:
- name: SANDBOX_USER_ID
value: "1000"
@ -164,7 +164,7 @@ spec:
ports:
- containerPort: 3000
- name: openhands-sandbox-2024
image: ghcr.io/all-hands-ai/sandbox:main
image: docker.all-hands.dev/all-hands-ai/runtime:main
ports:
- containerPort: 51963
command: ["/usr/sbin/sshd", "-D", "-p 51963", "-o", "PermitRootLogin=yes"]
@ -205,10 +205,10 @@ LAST SEEN TYPE REASON OBJECT
9s Normal SuccessfulAttachVolume pod/openhands-app-2024 AttachVolume.Attach succeeded for volume "pvc-2b1d223a-1c8f-4990-8e3d-68061a9ae252"
9s Normal SuccessfulAttachVolume pod/openhands-app-2024 AttachVolume.Attach succeeded for volume "pvc-31f15b25-faad-4665-a25f-201a530379af"
6s Normal AddedInterface pod/openhands-app-2024 Add eth0 [10.128.2.48/23] from openshift-sdn
6s Normal Pulled pod/openhands-app-2024 Container image "ghcr.io/all-hands-ai/openhands:main" already present on machine
6s Normal Pulled pod/openhands-app-2024 Container image "docker.all-hands.dev/all-hands-ai/openhands:main" already present on machine
6s Normal Created pod/openhands-app-2024 Created container openhands-app-2024
6s Normal Started pod/openhands-app-2024 Started container openhands-app-2024
6s Normal Pulled pod/openhands-app-2024 Container image "ghcr.io/all-hands-ai/sandbox:main" already present on machine
6s Normal Pulled pod/openhands-app-2024 Container image "docker.all-hands.dev/all-hands-ai/sandbox:main" already present on machine
5s Normal Created pod/openhands-app-2024 Created container openhands-sandbox-2024
5s Normal Started pod/openhands-app-2024 Started container openhands-sandbox-2024
83s Normal WaitForFirstConsumer persistentvolumeclaim/workspace-pvc waiting for first consumer to be created before binding
@ -334,7 +334,7 @@ spec:
spec:
containers:
- name: openhands-app-2024
image: ghcr.io/all-hands-ai/openhands:main
image: docker.all-hands.dev/all-hands-ai/openhands:main
env:
- name: SANDBOX_USER_ID
value: "1000"
@ -356,7 +356,7 @@ spec:
ports:
- containerPort: 3000
- name: openhands-sandbox-2024
image: ghcr.io/opendevin/sandbox:main
image: docker.all-hands.dev/all-hands-ai/runtime:main
# securityContext:
# privileged: true # Add this to allow privileged access
ports:

View File

@ -8,24 +8,18 @@
## Start the app
The easiest way to run OpenHands is in Docker. You can change `WORKSPACE_BASE` below to point OpenHands to
existing code that you'd like to modify.
The easiest way to run OpenHands is in Docker.
```bash
export WORKSPACE_BASE=$(pwd)/workspace
docker pull docker.all-hands.dev/all-hands-ai/runtime:0.11-nikolaik
docker pull ghcr.io/all-hands-ai/runtime:0.11-nikolaik
docker run -it --pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=ghcr.io/all-hands-ai/runtime:0.11-nikolaik \
-e SANDBOX_USER_ID=$(id -u) \
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \
-v $WORKSPACE_BASE:/opt/workspace_base \
docker run -it --rm --pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.11-nikolaik \
-v /var/run/docker.sock:/var/run/docker.sock \
-p 3000:3000 \
--add-host host.docker.internal:host-gateway \
--name openhands-app-$(date +%Y%m%d%H%M%S) \
ghcr.io/all-hands-ai/openhands:0.11
--name openhands-app \
docker.all-hands.dev/all-hands-ai/openhands:0.11
```
You can also run OpenHands in a scriptable [headless mode](https://docs.all-hands.dev/modules/usage/how-to/headless-mode), as an [interactive CLI](https://docs.all-hands.dev/modules/usage/how-to/cli-mode), or using the [OpenHands GitHub Action](https://docs.all-hands.dev/modules/usage/how-to/github-action).
@ -34,9 +28,6 @@ You can also run OpenHands in a scriptable [headless mode](https://docs.all-hand
After running the command above, you'll find OpenHands running at [http://localhost:3000](http://localhost:3000).
The agent will have access to the `./workspace` folder to do its work. You can copy existing code here, or change `WORKSPACE_BASE` in the
command to point to an existing folder.
Upon launching OpenHands, you'll see a settings modal. You **must** select an `LLM Provider` and `LLM Model` and enter a corresponding `API Key`.
These can be changed at any time by selecting the `Settings` button (gear icon) in the UI.
@ -52,9 +43,9 @@ The `Advanced Options` also allow you to specify a `Base URL` if required.
## Versions
The command above pulls the most recent stable release of OpenHands. You have other options as well:
- For a specific release, use `ghcr.io/all-hands-ai/openhands:$VERSION`, replacing $VERSION with the version number.
- For a specific release, use `docker.all-hands.dev/all-hands-ai/openhands:$VERSION`, replacing $VERSION with the version number.
- We use semver, and release major, minor, and patch tags. So `0.9` will automatically point to the latest `0.9.x` release, and `0` will point to the latest `0.x.x` release.
- For the most up-to-date development version, you can use `ghcr.io/all-hands-ai/openhands:main`. This version is unstable and is recommended for testing or development purposes only.
- For the most up-to-date development version, you can use `docker.all-hands.dev/all-hands-ai/openhands:main`. This version is unstable and is recommended for testing or development purposes only.
You can choose the tag that best suits your needs based on stability requirements and desired features.

View File

@ -35,32 +35,15 @@ Use the instructions [here](../getting-started) to start OpenHands using Docker.
But when running `docker run`, you'll need to add a few more arguments:
```bash
--add-host host.docker.internal:host-gateway \
-e LLM_OLLAMA_BASE_URL="http://host.docker.internal:11434" \
```
LLM_OLLAMA_BASE_URL is optional. If you set it, it will be used to show the available installed models in the UI.
Example:
```bash
# The directory you want OpenHands to modify. MUST be an absolute path!
export WORKSPACE_BASE=$(pwd)/workspace
docker run \
-it \
--pull=always \
docker run # ...
--add-host host.docker.internal:host-gateway \
-e SANDBOX_USER_ID=$(id -u) \
-e LLM_OLLAMA_BASE_URL="http://host.docker.internal:11434" \
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \
-v $WORKSPACE_BASE:/opt/workspace_base \
-v /var/run/docker.sock:/var/run/docker.sock \
-p 3000:3000 \
ghcr.io/all-hands-ai/openhands:main
# ...
```
You should now be able to connect to `http://localhost:3000/`
LLM_OLLAMA_BASE_URL is optional. If you set it, it will be used to show
the available installed models in the UI.
### Configure the Web Application
@ -176,18 +159,11 @@ CUSTOM_LLM_PROVIDER="openai"
### Docker
```bash
docker run \
-it \
--pull=always \
-e SANDBOX_USER_ID=$(id -u) \
docker run # ...
-e LLM_MODEL="openai/lmstudio" \
-e LLM_BASE_URL="http://host.docker.internal:1234/v1" \
-e CUSTOM_LLM_PROVIDER="openai" \
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \
-v $WORKSPACE_BASE:/opt/workspace_base \
-v /var/run/docker.sock:/var/run/docker.sock \
-p 3000:3000 \
ghcr.io/all-hands-ai/openhands:main
# ...
```
You should now be able to connect to `http://localhost:3000/`

View File

@ -0,0 +1,79 @@
# Runtime Configuration
A Runtime is an environment where the OpenHands agent can edit files and run
commands.
By default, OpenHands uses a Docker-based runtime, running on your local computer.
This means you only have to pay for the LLM you're using, and your code is only ever sent to the LLM.
We also support "remote" runtimes, which are typically managed by third-parties.
They can make setup a bit simpler and more scalable, especially
if you're running many OpenHands conversations in parallel (e.g. to do evaluation).
## Docker Runtime
This is the default Runtime that's used when you start OpenHands. You might notice
some flags being passed to `docker run` that make this possible:
```
docker run # ...
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.11-nikolaik \
-v /var/run/docker.sock:/var/run/docker.sock \
# ...
```
The `SANDBOX_RUNTIME_CONTAINER_IMAGE` from nikolaik is a pre-built runtime image
that contains our Runtime server, as well as some basic utilities for Python and NodeJS.
You can also [build your own runtime image](how-to/custom-sandbox-guide).
### Connecting to Your filesystem
One useful feature here is the ability to connect to your local filesystem.
To mount your filesystem into the runtime, add the following options to
the `docker run` command:
```bash
export WORKSPACE_BASE=/path/to/your/code
docker run # ...
-e SANDBOX_USER_ID=$(id -u) \
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \
-v $WORKSPACE_BASE:/opt/workspace_base \
# ...
```
Be careful! There's nothing stopping the OpenHands agent from deleting or modifying
any files that are mounted into its workspace.
This setup can cause some issues with file permissions (hence the `SANDBOX_USER_ID` variable)
but seems to work well on most systems.
## All Hands Runtime
The All Hands Runtime is currently in beta. You can request access by joining
the #remote-runtime-limited-beta channel on Slack (see the README for an invite).
To use the All Hands Runtime, set the following environment variables when
starting OpenHands:
```bash
docker run # ...
-e RUNTIME=remote \
-e SANDBOX_REMOTE_RUNTIME_API_URL="https://runtime.app.all-hands.dev" \
-e SANDBOX_API_KEY="your-all-hands-api-key" \
-e SANDBOX_KEEP_REMOTE_RUNTIME_ALIVE="true" \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.11-nikolaik \
# ...
```
## Modal Runtime
Our partners at [Modal](https://modal.com/) have also provided a runtime for OpenHands.
To use the Modal Runtime, create an account, and then [create an API key](https://modal.com/settings)
You'll then need to set the following environment variables when starting OpenHands:
```bash
docker run # ...
-e RUNTIME=modal \
-e MODAL_API_TOKEN_ID="your-id" \
-e MODAL_API_TOKEN_SECRET="your-secret" \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.11-nikolaik \
```

View File

@ -90,6 +90,11 @@ const sidebars: SidebarsConfig = {
},
],
},
{
type: 'doc',
label: 'Runtime Configuration',
id: 'usage/runtimes',
},
{
type: 'doc',
label: 'Custom Sandbox',

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,6 @@ from openhands.core.config.app_config import AppConfig
from openhands.core.config.config_utils import (
OH_DEFAULT_AGENT,
OH_MAX_ITERATIONS,
UndefinedString,
get_field_info,
)
from openhands.core.config.llm_config import LLMConfig
@ -22,7 +21,6 @@ from openhands.core.config.utils import (
__all__ = [
'OH_DEFAULT_AGENT',
'OH_MAX_ITERATIONS',
'UndefinedString',
'AgentConfig',
'AppConfig',
'LLMConfig',

View File

@ -1,4 +1,3 @@
import os
import uuid
from dataclasses import dataclass, field, fields, is_dataclass
from typing import ClassVar
@ -8,7 +7,6 @@ from openhands.core.config.agent_config import AgentConfig
from openhands.core.config.config_utils import (
OH_DEFAULT_AGENT,
OH_MAX_ITERATIONS,
UndefinedString,
get_field_info,
)
from openhands.core.config.llm_config import LLMConfig
@ -55,11 +53,8 @@ class AppConfig:
file_store: str = 'memory'
file_store_path: str = '/tmp/file_store'
trajectories_path: str | None = None
# TODO: clean up workspace path after the removal of ServerRuntime
workspace_base: str = os.path.join(os.getcwd(), 'workspace')
workspace_mount_path: str | None = (
UndefinedString.UNDEFINED # this path should always be set when config is fully loaded
) # when set to None, do not mount the workspace
workspace_base: str | None = None
workspace_mount_path: str | None = None
workspace_mount_path_in_sandbox: str = '/workspace'
workspace_mount_rewrite: str | None = None
cache_dir: str = '/tmp/cache'

View File

@ -1,4 +1,3 @@
from enum import Enum
from types import UnionType
from typing import get_args, get_origin
@ -6,10 +5,6 @@ OH_DEFAULT_AGENT = 'CodeActAgent'
OH_MAX_ITERATIONS = 100
class UndefinedString(str, Enum):
UNDEFINED = 'UNDEFINED'
def get_field_info(f):
"""Extract information about a dataclass field: type, optional, and default.

View File

@ -15,7 +15,6 @@ from openhands.core.config.app_config import AppConfig
from openhands.core.config.config_utils import (
OH_DEFAULT_AGENT,
OH_MAX_ITERATIONS,
UndefinedString,
)
from openhands.core.config.llm_config import LLMConfig
from openhands.core.config.sandbox_config import SandboxConfig
@ -191,16 +190,15 @@ def load_from_toml(cfg: AppConfig, toml_file: str = 'config.toml'):
def finalize_config(cfg: AppConfig):
"""More tweaks to the config after it's been loaded."""
cfg.workspace_base = os.path.abspath(cfg.workspace_base)
# Set workspace_mount_path if not set by the user
if cfg.workspace_mount_path is UndefinedString.UNDEFINED:
cfg.workspace_mount_path = cfg.workspace_base
if cfg.workspace_base is not None:
cfg.workspace_base = os.path.abspath(cfg.workspace_base)
if cfg.workspace_mount_path is None:
cfg.workspace_mount_path = cfg.workspace_base
if cfg.workspace_mount_rewrite: # and not config.workspace_mount_path:
# TODO why do we need to check if workspace_mount_path is None?
base = cfg.workspace_base or os.getcwd()
parts = cfg.workspace_mount_rewrite.split(':')
cfg.workspace_mount_path = base.replace(parts[0], parts[1])
if cfg.workspace_mount_rewrite:
base = cfg.workspace_base or os.getcwd()
parts = cfg.workspace_mount_rewrite.split(':')
cfg.workspace_mount_path = base.replace(parts[0], parts[1])
for llm in cfg.llms.values():
if llm.embedding_base_url is None:

View File

@ -205,11 +205,7 @@ class EventStreamRuntime(Runtime):
self.log(
'info', f'Starting runtime with image: {self.runtime_container_image}'
)
self._init_container(
sandbox_workspace_dir=self.config.workspace_mount_path_in_sandbox, # e.g. /workspace
mount_dir=self.config.workspace_mount_path, # e.g. /opt/openhands/_test_workspace
plugins=self.plugins,
)
self._init_container()
self.log('info', f'Container started: {self.container_name}')
else:
@ -246,19 +242,14 @@ class EventStreamRuntime(Runtime):
stop=tenacity.stop_after_attempt(5) | stop_if_should_exit(),
wait=tenacity.wait_exponential(multiplier=1, min=4, max=60),
)
def _init_container(
self,
sandbox_workspace_dir: str,
mount_dir: str | None = None,
plugins: list[PluginRequirement] | None = None,
):
def _init_container(self):
try:
self.log('debug', 'Preparing to start container...')
self.send_status_message('STATUS$PREPARING_CONTAINER')
plugin_arg = ''
if plugins is not None and len(plugins) > 0:
if self.plugins is not None and len(self.plugins) > 0:
plugin_arg = (
f'--plugins {" ".join([plugin.name for plugin in plugins])} '
f'--plugins {" ".join([plugin.name for plugin in self.plugins])} '
)
self._host_port = self._find_available_port()
@ -294,17 +285,27 @@ class EventStreamRuntime(Runtime):
environment['DEBUG'] = 'true'
self.log('debug', f'Workspace Base: {self.config.workspace_base}')
if mount_dir is not None and sandbox_workspace_dir is not None:
if (
self.config.workspace_mount_path is not None
and self.config.workspace_mount_path_in_sandbox is not None
):
# e.g. result would be: {"/home/user/openhands/workspace": {'bind': "/workspace", 'mode': 'rw'}}
volumes = {mount_dir: {'bind': sandbox_workspace_dir, 'mode': 'rw'}}
self.log('debug', f'Mount dir: {mount_dir}')
volumes = {
self.config.workspace_mount_path: {
'bind': self.config.workspace_mount_path_in_sandbox,
'mode': 'rw',
}
}
logger.debug(f'Mount dir: {self.config.workspace_mount_path}')
else:
self.log(
'warn',
'Warning: Mount dir is not set, will not mount the workspace directory to the container!\n',
logger.debug(
'Mount dir is not set, will not mount the workspace directory to the container'
)
volumes = None
self.log('debug', f'Sandbox workspace: {sandbox_workspace_dir}')
self.log(
'debug',
f'Sandbox workspace: {self.config.workspace_mount_path_in_sandbox}'
)
if self.config.sandbox.browsergym_eval_env is not None:
browsergym_arg = (
@ -319,7 +320,7 @@ class EventStreamRuntime(Runtime):
f'/openhands/micromamba/bin/micromamba run -n openhands '
f'poetry run '
f'python -u -m openhands.runtime.action_execution_server {self._container_port} '
f'--working-dir "{sandbox_workspace_dir}" '
f'--working-dir "{self.config.workspace_mount_path_in_sandbox}" '
f'{plugin_arg}'
f'--username {"openhands" if self.config.run_as_openhands else "root"} '
f'--user-id {self.config.sandbox.user_id} '

View File

@ -6,7 +6,6 @@ from openhands.core.config import (
AgentConfig,
AppConfig,
LLMConfig,
UndefinedString,
finalize_config,
get_llm_config_arg,
load_from_env,
@ -82,12 +81,8 @@ def test_load_from_old_style_env(monkeypatch, default_config):
assert default_config.get_agent_config().memory_enabled is True
assert default_config.default_agent == 'PlannerAgent'
assert default_config.workspace_base == '/opt/files/workspace'
assert (
default_config.workspace_mount_path is UndefinedString.UNDEFINED
) # before finalize_config
assert (
default_config.workspace_mount_path_in_sandbox is not UndefinedString.UNDEFINED
)
assert default_config.workspace_mount_path is None # before finalize_config
assert default_config.workspace_mount_path_in_sandbox is not None
assert default_config.sandbox.base_container_image == 'custom_image'
@ -148,11 +143,8 @@ default_agent = "TestAgent"
assert default_config.workspace_base == '/opt/files2/workspace'
assert default_config.sandbox.timeout == 1
# before finalize_config, workspace_mount_path is UndefinedString.UNDEFINED if it was not set
assert default_config.workspace_mount_path is UndefinedString.UNDEFINED
assert (
default_config.workspace_mount_path_in_sandbox is not UndefinedString.UNDEFINED
)
assert default_config.workspace_mount_path is None
assert default_config.workspace_mount_path_in_sandbox is not None
assert default_config.workspace_mount_path_in_sandbox == '/workspace'
finalize_config(default_config)
@ -231,8 +223,7 @@ sandbox_user_id = 1001
load_from_toml(default_config, temp_toml_file)
# before finalize_config, workspace_mount_path is UndefinedString.UNDEFINED if it was not set
assert default_config.workspace_mount_path is UndefinedString.UNDEFINED
assert default_config.workspace_mount_path is None
load_from_env(default_config, os.environ)
@ -244,11 +235,9 @@ sandbox_user_id = 1001
# after we set workspace_base to 'UNDEFINED' in the environment,
# workspace_base should be set to that
# workspace_mount path is still UndefinedString.UNDEFINED
assert default_config.workspace_base is not UndefinedString.UNDEFINED
assert default_config.workspace_base is not None
assert default_config.workspace_base == 'UNDEFINED'
assert default_config.workspace_mount_path is UndefinedString.UNDEFINED
assert default_config.workspace_mount_path == 'UNDEFINED'
assert default_config.workspace_mount_path is None
assert default_config.disable_color is True
assert default_config.sandbox.timeout == 1000
@ -284,8 +273,7 @@ user_id = 1001
load_from_toml(default_config, temp_toml_file)
# before finalize_config, workspace_mount_path is UndefinedString.UNDEFINED if it was not set
assert default_config.workspace_mount_path is UndefinedString.UNDEFINED
assert default_config.workspace_mount_path is None
# before load_from_env, values are set to the values from the toml file
assert default_config.get_llm_config().api_key == 'toml-api-key'
@ -338,9 +326,7 @@ user_id = 1001
def test_defaults_dict_after_updates(default_config):
# Test that `defaults_dict` retains initial values after updates.
initial_defaults = default_config.defaults_dict
assert (
initial_defaults['workspace_mount_path']['default'] is UndefinedString.UNDEFINED
)
assert initial_defaults['workspace_mount_path']['default'] is None
assert initial_defaults['default_agent']['default'] == 'CodeActAgent'
updated_config = AppConfig()
@ -352,10 +338,7 @@ def test_defaults_dict_after_updates(default_config):
defaults_after_updates = updated_config.defaults_dict
assert defaults_after_updates['default_agent']['default'] == 'CodeActAgent'
assert (
defaults_after_updates['workspace_mount_path']['default']
is UndefinedString.UNDEFINED
)
assert defaults_after_updates['workspace_mount_path']['default'] is None
assert defaults_after_updates['sandbox']['timeout']['default'] == 120
assert (
defaults_after_updates['sandbox']['base_container_image']['default']
@ -384,17 +367,16 @@ def test_invalid_toml_format(monkeypatch, temp_toml_file, default_config):
def test_finalize_config(default_config):
# Test finalize config
assert default_config.workspace_mount_path is UndefinedString.UNDEFINED
assert default_config.workspace_mount_path is None
default_config.workspace_base = None
finalize_config(default_config)
assert default_config.workspace_mount_path == os.path.abspath(
default_config.workspace_base
)
assert default_config.workspace_mount_path is None
# tests for workspace, mount path, path in sandbox, cache dir
def test_workspace_mount_path_default(default_config):
assert default_config.workspace_mount_path is UndefinedString.UNDEFINED
assert default_config.workspace_mount_path is None
default_config.workspace_base = '/home/user/project'
finalize_config(default_config)
assert default_config.workspace_mount_path == os.path.abspath(
default_config.workspace_base