Skip to content

Commit a19e4df

Browse files
authored
fix: terminal toolkit working_directory does not set in docker environment (#3181)
1 parent 8355c52 commit a19e4df

File tree

1 file changed

+51
-16
lines changed

1 file changed

+51
-16
lines changed

camel/toolkits/terminal_toolkit/terminal_toolkit.py

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -65,17 +65,27 @@ class TerminalToolkit(BaseToolkit):
6565
in either a local or a sandboxed Docker environment.
6666
6767
Args:
68-
use_docker_backend (bool): If True, all commands are executed in a
69-
Docker container. Defaults to False.
70-
docker_container_name (Optional[str]): The name of the Docker
71-
container to use. Required if use_docker_backend is True.
72-
working_dir (str): The base directory for all operations.
73-
For the local backend, this acts as a security sandbox.
74-
session_logs_dir (Optional[str]): The directory to store session
75-
logs. Defaults to a 'terminal_logs' subfolder in the
76-
working_dir.
77-
timeout (int): The default timeout in seconds for blocking
78-
commands. Defaults to 60.
68+
timeout (Optional[float]): The default timeout in seconds for blocking
69+
commands. Defaults to 20.0.
70+
working_directory (Optional[str]): The base directory for operations.
71+
For the local backend, this acts as a security sandbox.
72+
For the Docker backend, this sets the working directory inside
73+
the container.
74+
If not specified, defaults to "./workspace" for local and
75+
"/workspace" for Docker.
76+
use_docker_backend (bool): If True, all commands are executed in a
77+
Docker container. Defaults to False.
78+
docker_container_name (Optional[str]): The name of the Docker
79+
container to use. Required if use_docker_backend is True.
80+
session_logs_dir (Optional[str]): The directory to store session
81+
logs. Defaults to a 'terminal_logs' subfolder in the
82+
working directory.
83+
safe_mode (bool): Whether to apply security checks to commands.
84+
Defaults to True.
85+
allowed_commands (Optional[List[str]]): List of allowed commands
86+
when safe_mode is True. If None, uses default safety rules.
87+
clone_current_env (bool): Whether to clone the current Python
88+
environment for local execution. Defaults to False.
7989
"""
8090

8191
def __init__(
@@ -95,15 +105,34 @@ def __init__(
95105
# Thread-safe guard for concurrent access to
96106
# shell_sessions and session state
97107
self._session_lock = threading.RLock()
98-
if working_directory:
99-
self.working_dir = os.path.abspath(working_directory)
100-
else:
108+
109+
# Initialize docker_workdir with proper type
110+
self.docker_workdir: Optional[str] = None
111+
112+
if self.use_docker_backend:
113+
# For Docker backend, working_directory is path inside container
114+
if working_directory:
115+
self.docker_workdir = working_directory
116+
else:
117+
self.docker_workdir = "/workspace"
118+
# For logs and local file operations, use a local workspace
101119
camel_workdir = os.environ.get("CAMEL_WORKDIR")
102120
if camel_workdir:
103121
self.working_dir = os.path.abspath(camel_workdir)
104122
else:
105123
self.working_dir = os.path.abspath("./workspace")
124+
else:
125+
# For local backend, working_directory is the local path
126+
if working_directory:
127+
self.working_dir = os.path.abspath(working_directory)
128+
else:
129+
camel_workdir = os.environ.get("CAMEL_WORKDIR")
130+
if camel_workdir:
131+
self.working_dir = os.path.abspath(camel_workdir)
132+
else:
133+
self.working_dir = os.path.abspath("./workspace")
106134

135+
# Only create local directory for logs and local backend operations
107136
if not os.path.exists(self.working_dir):
108137
os.makedirs(self.working_dir, exist_ok=True)
109138
self.safe_mode = safe_mode
@@ -506,8 +535,11 @@ def shell_exec(self, id: str, command: str, block: bool = True) -> str:
506535
)
507536
else:
508537
# DOCKER BLOCKING
538+
assert (
539+
self.docker_workdir is not None
540+
) # Docker backend always has workdir
509541
exec_instance = self.docker_api_client.exec_create(
510-
self.container.id, command, workdir="/workspace"
542+
self.container.id, command, workdir=self.docker_workdir
511543
)
512544
exec_output = self.docker_api_client.exec_start(
513545
exec_instance['Id']
@@ -574,12 +606,15 @@ def shell_exec(self, id: str, command: str, block: bool = True) -> str:
574606
with self._session_lock:
575607
self.shell_sessions[session_id]["process"] = process
576608
else:
609+
assert (
610+
self.docker_workdir is not None
611+
) # Docker backend always has workdir
577612
exec_instance = self.docker_api_client.exec_create(
578613
self.container.id,
579614
command,
580615
stdin=True,
581616
tty=True,
582-
workdir="/workspace",
617+
workdir=self.docker_workdir,
583618
)
584619
exec_id = exec_instance['Id']
585620
exec_socket = self.docker_api_client.exec_start(

0 commit comments

Comments
 (0)