Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion crewai_tools/tools/code_interpreter_tool/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ This tool is used to give the Agent the ability to run code (Python3) from the c

It is incredible useful since it allows the Agent to generate code, run it in the same environment, get the result and use it to make decisions.

> [!CAUTION]
> By default, the CodeInterpreterTool will mount and provide read/write access to your current working directory. This means the executed code can access, modify, or delete any files in your project directory. To limit access to a specific folder, use the `mount_path` parameter to specify which directory should be mounted instead.
>
## Requirements

- Docker

## Installation
Expand Down Expand Up @@ -51,3 +53,14 @@ Agent(
)

```

To limit file system access to a specific directory, use the `mount_path` parameter:

```python
from crewai_tools import CodeInterpreterTool

Agent(
...
tools=[CodeInterpreterTool(mount_path="./data")], # Only provides access to ./data folder
)
```
39 changes: 36 additions & 3 deletions crewai_tools/tools/code_interpreter_tool/code_interpreter_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import importlib.util
import os
from pathlib import Path
from types import ModuleType
from typing import Any, Dict, List, Optional, Type

Expand Down Expand Up @@ -142,6 +143,7 @@ class CodeInterpreterTool(BaseTool):
user_dockerfile_path: Optional[str] = None
user_docker_base_url: Optional[str] = None
unsafe_mode: bool = False
mount_path: Optional[str] = None

@staticmethod
def _get_installed_package_path() -> str:
Expand Down Expand Up @@ -222,14 +224,45 @@ def _init_docker_container(self) -> Container:
"""Initializes and returns a Docker container for code execution.

Stops and removes any existing container with the same name before creating
a new one. Maps the current working directory to /workspace in the container.
a new one. Mounts the specified mount_path (relative to cwd) if provided,
otherwise defaults to the current working directory

Returns:
A Docker container object ready for code execution.
"""
container_name = "code-interpreter"
client = docker_from_env()
current_path = os.getcwd()
current_path = Path.cwd()

# if mount_path is provided, mount that, else mount the current working directory
mount_dir = current_path # Default to current directory

if self.mount_path and self.mount_path.strip():
try:
proposed_mount_dir = (current_path / self.mount_path).resolve()

# check if the mount_dir is valid
if not proposed_mount_dir.exists() or not proposed_mount_dir.is_dir():
Printer.print(
f"Warning: Invalid mount directory: {proposed_mount_dir}. Using current directory instead.",
color="yellow",
)
# check if the mount_dir is within the current working directory to prevent escapes
elif (
current_path not in proposed_mount_dir.parents
and proposed_mount_dir != current_path
):
Printer.print(
f"Warning: {proposed_mount_dir} is outside the project root. Using current directory instead.",
color="yellow",
)
else:
mount_dir = proposed_mount_dir
except Exception as e:
Printer.print(
f"Warning: Error resolving mount path '{self.mount_path}': {e}. Using current directory instead.",
color="yellow",
)

# Check if the container is already running
try:
Expand All @@ -245,7 +278,7 @@ def _init_docker_container(self) -> Container:
tty=True,
working_dir="/workspace",
name=container_name,
volumes={current_path: {"bind": "/workspace", "mode": "rw"}}, # type: ignore
volumes={mount_dir: {"bind": "/workspace", "mode": "rw"}}, # type: ignore
)

def _check_docker_available(self) -> bool:
Expand Down