@@ -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