-
Notifications
You must be signed in to change notification settings - Fork 5.9k
feature: Add "!cmd" user shell execution #2471
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
All contributors have signed the CLA ✍️ ✅ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Codex Review: Here are some suggestions.
Reply with @codex fix comments
to fix any unresolved comments.
About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you open a pull request that is ready for review, or mark a draft as ready for review. You can also ask for a review by commenting "@codex review".
Codex can also answer questions or update the PR. Try commenting "@codex fix this CI failure" or "@codex address that feedback".
We need to make sure cancellation works, particularly ctr-c. Right now it doesn't actually cancel the command. If possible, we should show the command we just ran + any output and delineate it as a user command instead of using the shortening UI we do for the model. Otherwise nice work! |
This also doesn't support windows, which isn't necessarily a blocker but we might need to look at. |
Happy to send a patch with both! Wanted to get something out to get buy-in first. Thanks for the prompt feedback. |
This is great! Would be also fantastic to have a way to run background commands like with Claude Code and have the output continuously attached to any new messages.
Here is also a good description of the feature: sst/opencode#1970 |
7318b7e
to
31a20a2
Compare
I have read the CLA Document and I hereby sign the CLA |
Alright both those things should work. Also, the Tui still remains like the "frontend" and forwards the request to the "core". This is in line with the existing archiecture. |
Summary
Notes
Review
Follow-up (outside this PR scope)
|
@codex review in depth |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Codex Review: Here are some suggestions.
Reply with @codex fix comments
to fix any unresolved comments.
About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you open a pull request for review, mark a draft as ready, or comment "@codex review". If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex fix this CI failure" or "@codex address that feedback".
Seems worth addressing the codex review notes above ^ |
18d2af7
to
fec03bc
Compare
Fixed. |
@codex review in depth |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Codex Review: Here are some suggestions.
Reply with @codex fix comments
to fix any unresolved comments.
About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you open a pull request for review, mark a draft as ready, or comment "@codex review". If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex fix this CI failure" or "@codex address that feedback".
771ae55
to
8aaf9f0
Compare
All fixed! |
8aaf9f0
to
1f4d16f
Compare
Does this pull request have a planned release schedule? When I was using a different coding agent, I was able to provide the necessary context with the ! command—for example, executing database queries or checking schemas. Supplying context through the ! command also helped the coding agent experiment autonomously. With Codex, I’ve been following this workflow by copying and pasting from the shell, which requires some additional steps. For that reason, I’m very much looking forward to the release of this feature. |
As discussed offline, I think this needs a new approach that uses more of the existing |
b72c0da
to
9518387
Compare
@bolinfest Updated the implementation to align with our discussion offline |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please add a video to the PR body?
Actively working to land this. |
Thank you, I really appreciate it. I’m looking forward to trying it out. |
e973899
to
dbd41cc
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed all comments
Fix for CI failure (seems like a flake) - #3844 |
Also done |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is generally good, but there are some things I'd like you to look at!
codex-rs/protocol/src/protocol.rs
Outdated
assert_eq!(deserialized, event); | ||
} | ||
|
||
#[test] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can do without this test: it doesn't provide much in the way of additional code correctness.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
codex-rs/protocol/src/protocol.rs
Outdated
/// True when this exec was initiated directly by the user (e.g. bang command), | ||
/// not by the agent/model. Defaults to false for backwards compatibility. | ||
#[serde(default)] | ||
pub user_initiated_shell_command: bool, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about: is_user_shell_command
to mirror the name of the Op
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
codex-rs/tui/src/chatwidget.rs
Outdated
struct RunningCommand { | ||
command: Vec<String>, | ||
parsed_cmd: Vec<ParsedCommand>, | ||
user_initiated_shell_command: bool, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rename this as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
codex-rs/tui/src/chatwidget.rs
Outdated
// Special-case: "!cmd" executes a local shell command instead of sending to the model. | ||
if let Some(stripped) = text.strip_prefix('!') { | ||
let cmd = stripped.trim().to_string(); | ||
if !cmd.is_empty() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So if the user types !
by itself, we'll send the message "!"
to the agent, correct?
I guess this is fine, though we could take this opportunity to tell the user about the !
feature instead?
codex-rs/tui/src/history_cell.rs
Outdated
body_lines.extend(wrapped.into_iter().map(|l| Line::from(l.to_string().dim()))); | ||
|
||
if let Some(output) = call.output.as_ref() { | ||
let is_shell_exec_cell = self.calls.iter().any(|c| c.user_initiated_shell_command); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we believe we could have a mix of exec calls in flight, only some of which are user initiated shell commands?
codex-rs/core/src/codex.rs
Outdated
sub_id: String, | ||
command: String, | ||
) { | ||
let spawn_sub_id = sub_id.clone(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do this inside let handle
, as well?
unsafe { | ||
std::env::set_var("CODEX_HERMETIC_TEST_SHELL", "1"); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please find another way to do this: this is unsafe
for a reason.
use std::path::PathBuf; | ||
use tempfile::TempDir; | ||
|
||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please omit worker_threads
unless you have a reason to believe you need them.
Empirically, tests that only pass with more than one worker thread imply bugs in our code, so I would prefer to try to catch them.
@@ -0,0 +1,119 @@ | |||
#![cfg(unix)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given these tests are limited to unix for now (which I would prefer not to do), do we really need CODEX_HERMETIC_TEST_SHELL
?
// 1) ls should list the file | ||
codex | ||
.submit(Op::RunUserShellCommand { | ||
command: "ls".to_string(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I often use python3 -c
as an example for cross-platform shell calls.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
0bc6e90
to
2f0bc51
Compare
Any update on the merge timeline for this PR? |
- protocol: add Op::RunUserShellCommand to model a user-initiated one-off command - core: handle new Op by spawning a cancellable task that runs the command using the user’s default shell; stream output via ExecCommand* events; send TaskStarted/TaskComplete; track as current_task so Interrupt works - tui: detect leading '!' in composer submission and dispatch Op::RunUserShellCommand instead of sending a user message No changes to sandbox env var behavior; uses existing exec pipeline and event types.
5578dbe
to
45dc4f1
Compare
protocol: add Op::RunUserShellCommand to model a user-initiated one-off command
core: handle new Op by spawning a cancellable task that runs the command using the user’s default shell; stream output via ExecCommand* events; send TaskStarted/TaskComplete; track as current_task so Interrupt works
tui: detect leading '!' in composer submission and dispatch Op::RunUserShellCommand instead of sending a user message
No changes to sandbox env var behavior; uses existing exec pipeline and event types.
Handles Ctrl-C to send SIGINT to the user command
Handles limiting output from a user command to not overflow the tui
Demo video
bang-command-demo-video-1080p.mp4