mirror of
https://github.com/openai/codex.git
synced 2026-05-01 18:06:47 +00:00
feat: shell_command tool (#6510)
This adds support for a new variant of the shell tool behind a flag. To
test, run `codex` with `--enable shell_command_tool`, which will
register the tool with Codex under the name `shell_command` that accepts
the following shape:
```python
{
command: str
workdir: str | None,
timeout_ms: int | None,
with_escalated_permissions: bool | None,
justification: str | None,
}
```
This is comparable to the existing tool registered under
`shell`/`container.exec`. The primary difference is that it accepts
`command` as a `str` instead of a `str[]`. The `shell_command` tool
executes by running `execvp(["bash", "-lc", command])`, though the exact
arguments to `execvp(3)` depend on the user's default shell.
The hypothesis is that this will simplify things for the model. For
example, on Windows, instead of generating:
```json
{"command": ["pwsh.exe", "-NoLogo", "-Command", "ls -Name"]}
```
The model could simply generate:
```json
{"command": "ls -Name"}
```
As part of this change, I extracted some logic out of `user_shell.rs` as
`Shell::derive_exec_args()` so that it can be reused in
`codex-rs/core/src/tools/handlers/shell.rs`. Note the original code
generated exec arg lists like:
```javascript
["bash", "-lc", command]
["zsh", "-lc", command]
["pwsh.exe", "-NoProfile", "-Command", command]
```
Using `-l` for Bash and Zsh, but then specifying `-NoProfile` for
PowerShell seemed inconsistent to me, so I changed this in the new
implementation while also adding a `use_login_shell: bool` option to
make this explicit. If we decide to add a `login: bool` to
`ShellCommandToolCallParams` like we have for unified exec:
807e2c27f0/codex-rs/core/src/tools/handlers/unified_exec.rs (L33-L34)
Then this should make it straightforward to support.
This commit is contained in:
@@ -63,27 +63,10 @@ impl SessionTask for UserShellCommandTask {
|
||||
// Execute the user's script under their default shell when known; this
|
||||
// allows commands that use shell features (pipes, &&, redirects, etc.).
|
||||
// We do not source rc files or otherwise reformat the script.
|
||||
let shell_invocation = match session.user_shell() {
|
||||
crate::shell::Shell::Zsh(zsh) => vec![
|
||||
zsh.shell_path.clone(),
|
||||
"-lc".to_string(),
|
||||
self.command.clone(),
|
||||
],
|
||||
crate::shell::Shell::Bash(bash) => vec![
|
||||
bash.shell_path.clone(),
|
||||
"-lc".to_string(),
|
||||
self.command.clone(),
|
||||
],
|
||||
crate::shell::Shell::PowerShell(ps) => vec![
|
||||
ps.exe.clone(),
|
||||
"-NoProfile".to_string(),
|
||||
"-Command".to_string(),
|
||||
self.command.clone(),
|
||||
],
|
||||
crate::shell::Shell::Unknown => {
|
||||
shlex::split(&self.command).unwrap_or_else(|| vec![self.command.clone()])
|
||||
}
|
||||
};
|
||||
let use_login_shell = true;
|
||||
let shell_invocation = session
|
||||
.user_shell()
|
||||
.derive_exec_args(&self.command, use_login_shell);
|
||||
|
||||
let call_id = Uuid::new_v4().to_string();
|
||||
let raw_command = self.command.clone();
|
||||
|
||||
Reference in New Issue
Block a user