Skip to content

Commit

Permalink
change mode names; opt docker building
Browse files Browse the repository at this point in the history
  • Loading branch information
liqul committed Mar 4, 2024
1 parent e5597b5 commit 97ca18b
Show file tree
Hide file tree
Showing 13 changed files with 78 additions and 73 deletions.
2 changes: 1 addition & 1 deletion ces_container/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ COPY taskweaver/ces /app/taskweaver/ces
COPY taskweaver/plugin /app/taskweaver/plugin
COPY taskweaver/module /app/taskweaver/module
COPY taskweaver/__init__.py /app/taskweaver/__init__.py
COPY docker_entry.py /app/docker_entry.py
COPY ces_container/docker_entry.py /app/docker_entry.py

ENV PYTHONPATH "${PYTHONPATH}:/app"

Expand Down
20 changes: 0 additions & 20 deletions ces_container/build.ps1

This file was deleted.

20 changes: 0 additions & 20 deletions ces_container/build.sh

This file was deleted.

20 changes: 20 additions & 0 deletions scripts/build.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
$scriptDirectory = $PSScriptRoot
Write-Host "The script directory is: $scriptDirectory"

$imageName = "taskweaver/executor"
$taskweaverPath = Join-Path -Path $scriptDirectory -ChildPath "..\taskweaver"
$dockerfilePath = Join-Path -Path $scriptDirectory -ChildPath "..\ces_container\Dockerfile"
$contextPath = Join-Path -Path $scriptDirectory -ChildPath "..\"

if (Test-Path $taskweaverPath) {
Write-Host "Found module files from $taskweaverPath"
Write-Host "Dockerfile path: $dockerfilePath"
Write-Host "Context path: $contextPath"
} else {
Write-Host "Local files not found."
exit 1
}

# Build the Docker image
docker build -t $imageName -f $dockerfilePath $contextPath

22 changes: 22 additions & 0 deletions scripts/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/bin/bash

# Get the directory containing the script file
scriptDirectory="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
echo "The script directory is: $scriptDirectory"

imageName="taskweaver/executor"
taskweaverPath="$scriptDirectory/../taskweaver"
dockerfilePath="$scriptDirectory/../ces_container/Dockerfile"
contextPath="$scriptDirectory/../"

if [ -d "$taskweaverPath" ]; then
echo "Found module files from $taskweaverPath"
echo "Dockerfile path: $dockerfilePath"
echo "Context path: $contextPath"
else
echo "Local files not found."
exit 1
fi

# Build the Docker image
docker build -t "$imageName" -f "$dockerfilePath" "$contextPath"
2 changes: 1 addition & 1 deletion taskweaver/ces/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

def code_execution_service_factory(
env_dir: str,
kernel_mode: Literal["SubProcess", "Container"] = "SubProcess",
kernel_mode: Literal["local", "container"] = "local",
) -> Manager:
return SubProcessManager(
env_dir=env_dir,
Expand Down
10 changes: 5 additions & 5 deletions taskweaver/ces/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ def pre_start_kernel(


class EnvMode(enum.Enum):
SubProcess = "subprocess"
Local = "local"
InsideContainer = "inside_container"
OutsideContainer = "outside_container"

Expand All @@ -132,14 +132,14 @@ def __init__(
self,
env_id: Optional[str] = None,
env_dir: Optional[str] = None,
env_mode: Optional[EnvMode] = EnvMode.SubProcess,
env_mode: Optional[EnvMode] = EnvMode.Local,
port_start_inside_container: Optional[int] = 12345,
) -> None:
self.session_dict: Dict[str, EnvSession] = {}
self.id = get_id(prefix="env") if env_id is None else env_id
self.env_dir = env_dir if env_dir is not None else os.getcwd()
self.mode = env_mode
if self.mode == EnvMode.SubProcess or self.mode == EnvMode.InsideContainer:
if self.mode == EnvMode.Local or self.mode == EnvMode.InsideContainer:
self.multi_kernel_manager = TaskWeaverMultiKernelManager(
default_kernel_name="taskweaver",
kernel_spec_manager=KernelSpecProvider(),
Expand Down Expand Up @@ -195,7 +195,7 @@ def start_session(
kernel_id_inside_container: Optional[str] = None,
port_start_inside_container: Optional[int] = None,
) -> None:
if self.mode == EnvMode.SubProcess:
if self.mode == EnvMode.Local:
session = self._get_session(session_id, session_dir=session_dir)
ces_session_dir = os.path.join(session.session_dir, "ces")
new_kernel_id = get_id(prefix="knl")
Expand Down Expand Up @@ -446,7 +446,7 @@ def stop_session(self, session_id: str) -> None:
return
try:
if session.kernel_id != "":
if self.mode == EnvMode.SubProcess or self.mode == EnvMode.InsideContainer:
if self.mode == EnvMode.Local or self.mode == EnvMode.InsideContainer:
kernel = self.multi_kernel_manager.get_kernel(session.kernel_id)
is_alive = kernel.is_alive()
if is_alive:
Expand Down
8 changes: 4 additions & 4 deletions taskweaver/ces/manager/sub_proc.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,16 @@ def __init__(
self,
env_id: Optional[str] = None,
env_dir: Optional[str] = None,
kernel_mode: Optional[Literal["SubProcess", "Container"]] = "SubProcess",
kernel_mode: Optional[Literal["local", "container"]] = "local",
) -> None:
env_id = env_id or os.getenv("TASKWEAVER_ENV_ID", "local")
env_dir = env_dir or os.getenv(
"TASKWEAVER_ENV_DIR",
os.path.realpath(os.getcwd()),
)
if kernel_mode == "SubProcess":
env_mode = EnvMode.SubProcess
elif kernel_mode == "Container":
if kernel_mode == "local":
env_mode = EnvMode.Local
elif kernel_mode == "container":
env_mode = EnvMode.OutsideContainer
else:
raise ValueError(f"Invalid kernel mode: {kernel_mode}, expected 'SubProcess' or 'Container'.")
Expand Down
4 changes: 2 additions & 2 deletions taskweaver/chat/console/chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -482,10 +482,10 @@ def _load_file(self, file_to_load: str):

def _reset_session(self, first_session: bool = False):
if not first_session:
self._system_message(f"--- stopping the current session {self.session.session_id} ---")
self._system_message("--- stopping the current session ---")
self.session.stop()
self.session = self.app.get_session()
self._system_message(f"--- new session starts {self.session.session_id} ---")
self._system_message("--- new session starts ---")

self._assistant_message(
"I am TaskWeaver, an AI assistant. To get started, could you please enter your request?",
Expand Down
2 changes: 1 addition & 1 deletion taskweaver/module/execution_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def _configure(self) -> None:
)
self.kernel_mode = self._get_str(
"kernel_mode",
"SubProcess",
"local",
)


Expand Down
2 changes: 1 addition & 1 deletion tests/unit_tests/test_environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def test_environment_start_subprocess():
cwd = os.path.dirname(os.path.abspath(__file__))
sessions = os.path.join(cwd, "sessions")
try:
env = Environment("local", env_mode=EnvMode.SubProcess)
env = Environment("local", env_mode=EnvMode.Local)
env.start_session(
session_id="session_id",
)
Expand Down
37 changes: 20 additions & 17 deletions website/docs/code_execution.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,41 @@

TaskWeaver is a code-first agent framework, which means that it always converts the user request into code
and executes the code to generate the response. In our current implementation, we use a Jupyter Kernel
to execute the code. We choose Jupyter Kernel because it is a well-established tool for interactive computing
to execute the code. We choose Jupyter Kernel because it is a well-established tool for interactive computing,
and it supports many programming languages.

## Two Modes of Code Execution

TaskWeaver supports two modes of code execution: `SubProcess` and `Container`.
The `SubProcess` mode is the default mode. The key difference between the two modes is that the `Container` mode
executes the code in a Docker container, which provides a more secure environment for code execution, while
the `SubProcess` mode executes the code as a subprocess of the TaskWeaver process.
As a result, in the `SubProcess` mode, if the user has malicious intent, the user could potentially
TaskWeaver supports two modes of code execution: `local` and `container`.
The `local` mode is the default mode. The key difference between the two modes is that the `container` mode
executes the code inside a Docker container, which provides a more secure environment for code execution, while
the `local` mode executes the code as a subprocess of the TaskWeaver process.
As a result, in the `local` mode, if the user has malicious intent, the user could potentially
instruct TaskWeaver to execute harmful code on the host machine. In addition, the LLM could also generate
harmful code, leading to potential security risks.

>💡We recommend using the `Container` mode for code execution, especially when the usage of the agent
is open to untrusted users. In the `Container` mode, the code is executed in a Docker container, which is isolated
>💡We recommend using the `container` mode for code execution, especially when the usage of the agent
is open to untrusted users. In the `container` mode, the code is executed in a Docker container, which is isolated
from the host machine.

## How to Configure the Code Execution Mode

To configure the code execution mode, you need to set the `execution_service.kernel_mode` parameter in the
`taskweaver_config.json` file. The value of the parameter could be `SubProcess` or `Container`. The default value
is `SubProcess`.
`taskweaver_config.json` file. The value of the parameter could be `local` or `container`. The default value
is `local`.

TaskWeaver supports the `SubProcess` mode without any additional setup. However, to use the `Container` mode,
TaskWeaver supports the `local` mode without any additional setup. However, to use the `container` mode,
there are a few prerequisites:

- Docker is installed on the host machine.
- A Docker image is built and available on the host machine for code execution.
- The `execution_service.kernel_mode` parameter is set to `Container` in the `taskweaver_config.json` file.
- The `execution_service.kernel_mode` parameter is set to `container` in the `taskweaver_config.json` file.

Once the code repository is cloned to your local machine, you can build the Docker image
by running the following command in the root directory of the code repository:

```bash
cd ces_container
cd scripts

# based on your OS
./build.ps1 # for Windows
Expand All @@ -45,13 +45,16 @@ cd ces_container

After the Docker image is built, you can run `docker images` to check if a Docker image
named `executor_container` is available.
If the prerequisite is met, you can now run TaskWeaver in the `Container` mode.
If the prerequisite is met, you can now run TaskWeaver in the `container` mode.

## Limitations of the `Container` Mode
After running TaskWeaver in the `container` mode, you can check if the container is running by running `docker ps`.
You should see a container of image `taskweaver/executor` running after executing some code.

The `Container` mode is more secure than the `SubProcess` mode, but it also has some limitations:
## Limitations of the `container` Mode

- The startup time of the `Container` mode is longer than the `SubProcess` mode, because it needs to start a Docker container.
The `container` mode is more secure than the `local` mode, but it also has some limitations:

- The startup time of the `container` mode is longer than the `local` mode, because it needs to start a Docker container.
- As the Jupyter Kernel is running inside a Docker container, it has limited access to the host machine. We are mapping the
`project/workspace/sessions/<session_id>` directory to the container, so the code executed in the container can access the
files in it. One implication of this is that the user cannot ask the agent to load a file from the host machine, because the
Expand Down
2 changes: 1 addition & 1 deletion website/docs/configurations.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ The following table lists the parameters in the configuration file:
| `session.code_gen_mode` | The code generation mode, could be `python`, `plugin_only` or `cli_only`, which means generating python code or only generating plugin functions or CLI commands. | `python` |
| `round_compressor.rounds_to_compress` | The number of rounds to compress. | `2` |
| `round_compressor.rounds_to_retain` | The number of rounds to retain. | `3` |
| `execution_service.kernel_mode` | The mode of the code executor, could be `SubProcess` or `Container`. | `SubProcess` |
| `execution_service.kernel_mode` | The mode of the code executor, could be `local` or `container`. | `local` |

> 💡 $\{AppBaseDir\} is the project directory.
Expand Down

0 comments on commit 97ca18b

Please sign in to comment.