Skip to content

Add thread/shellCommand to app server API surface#14988

Merged
etraut-openai merged 17 commits intomainfrom
etraut/threadshellcommand
Mar 19, 2026
Merged

Add thread/shellCommand to app server API surface#14988
etraut-openai merged 17 commits intomainfrom
etraut/threadshellcommand

Conversation

@etraut-openai
Copy link
Collaborator

@etraut-openai etraut-openai commented Mar 17, 2026

This PR adds a new thread/shellCommand app server API so clients can implement ! shell commands. These commands are executed within the sandbox, and the command text and output are visible to the model.

The internal implementation mirrors the current TUI ! behavior.

  • persist shell command execution as CommandExecution thread items, including source and formatted output metadata
  • bridge live and replayed app-server command execution events back into the existing tui_app_server exec rendering path

This PR also wires tui_app_server to submit ! commands through the new API.

@etraut-openai etraut-openai marked this pull request as ready for review March 17, 2026 20:59
@etraut-openai
Copy link
Collaborator Author

@codex review

@etraut-openai etraut-openai force-pushed the etraut/threadshellcommand branch from 89bb769 to 15be728 Compare March 17, 2026 21:02
Copy link
Contributor

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

event.formatted_output.clear();

P2 Badge Preserve formatted command output when persisting rollouts

thread/shellCommand adds formatted_output to CommandExecution, but rollout sanitization still clears it before persistence. As a result, thread/read and snapshot replay lose model-formatted exec text after reload/thread switch, despite the new API surfacing this field. This causes replayed command output to differ from live output and drops truncation/format metadata.

ℹ️ 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
  • 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 address that feedback".

@etraut-openai etraut-openai changed the title Add thread-scoped shell commands to the app server TUI Add thread/shellCommand to app server API surface Mar 17, 2026
etraut-openai added a commit that referenced this pull request Mar 17, 2026
@etraut-openai
Copy link
Collaborator Author

@codex review

Copy link
Contributor

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

let delta = String::from_utf8_lossy(&exec_command_output_delta_event.chunk).to_string();

P1 Badge Preserve raw bytes when forwarding command output deltas

ExecCommandOutputDelta chunks are converted with String::from_utf8_lossy(...) before emission. Non-UTF8 bytes are replaced with U+FFFD, then later re-encoded, so output is irreversibly corrupted. Because exec legacy events are now shadowed in the TUI adapter, clients no longer have a lossless fallback path for these chunks.

ℹ️ 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
  • 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 address that feedback".

etraut-openai added a commit that referenced this pull request Mar 17, 2026
@etraut-openai etraut-openai force-pushed the etraut/threadshellcommand branch from 731792e to 0341d1d Compare March 17, 2026 22:46
@etraut-openai
Copy link
Collaborator Author

@codex review

Copy link
Contributor

@chatgpt-codex-connector chatgpt-codex-connector bot left a 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 automated review suggestions for this pull request.

Reviewed commit: 0341d1d6d0

ℹ️ 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
  • 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 address that feedback".

@etraut-openai
Copy link
Collaborator Author

@codex review

etraut-openai added a commit that referenced this pull request Mar 17, 2026
etraut-openai added a commit that referenced this pull request Mar 17, 2026
etraut-openai added a commit that referenced this pull request Mar 17, 2026
etraut-openai added a commit that referenced this pull request Mar 18, 2026
etraut-openai added a commit that referenced this pull request Mar 18, 2026
etraut-openai added a commit that referenced this pull request Mar 18, 2026
@etraut-openai etraut-openai force-pushed the etraut/threadshellcommand branch from 548529a to 5b23c8d Compare March 18, 2026 17:18
etraut-openai added a commit that referenced this pull request Mar 18, 2026
etraut-openai added a commit that referenced this pull request Mar 18, 2026
@etraut-openai etraut-openai requested a review from owenlin0 March 18, 2026 17:36
#[ts(export_to = "v2/")]
pub struct ThreadShellCommandParams {
pub thread_id: String,
pub command: String,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, we use this for command/exec, should we be consistent?

    /// Command argv vector. Empty arrays are rejected.
    pub command: Vec<String>,

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

command/exec requires the caller to do their own shell expansion. This new call assumes that the string will be sent to the shell "as is" for interpretation by the shell itself. I don't think it makes sense to make this a vector of strings in this case.

aggregated_output: Option<String>,
/// The command's output after applying the model-facing formatter/truncation policy.
#[serde(default)]
formatted_output: String,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to expose this? I'd avoid, since this could bloat the payload quite a bit. Could we just rely on the existing aggregated_output?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I've changed this.

#[serde_as(as = "serde_with::base64::Base64")]
#[schemars(with = "String")]
#[ts(type = "string")]
pub delta: Vec<u8>,
Copy link
Collaborator

@owenlin0 owenlin0 Mar 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm this seems like it could be a breaking change

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After thinking about this more, I don't think that clients are generally going to be able to do much with raw byte output anyway. We'll stick with best-effort conversion to u8 text. I've undone the change to this structure.

Copy link
Contributor

@chatgpt-codex-connector chatgpt-codex-connector bot left a 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 automated review suggestions for this pull request.

Reviewed commit: 66af6244ad

ℹ️ 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
  • 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 address that feedback".

Copy link
Contributor

@chatgpt-codex-connector chatgpt-codex-connector bot left a 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 automated review suggestions for this pull request.

Reviewed commit: 502037815c

ℹ️ 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
  • 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 address that feedback".

@etraut-openai etraut-openai force-pushed the etraut/threadshellcommand branch from 91c5b21 to acb0aa0 Compare March 18, 2026 20:59
@etraut-openai etraut-openai requested a review from owenlin0 March 18, 2026 20:59
Copy link
Collaborator

@owenlin0 owenlin0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm!

}
EventMsg::ExecCommandOutputDelta(exec_command_output_delta_event) => {
let item_id = exec_command_output_delta_event.call_id.clone();
let delta = String::from_utf8_lossy(&exec_command_output_delta_event.chunk).to_string();
Copy link
Collaborator

@owenlin0 owenlin0 Mar 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: felt cleaner to keep it at the top. non-blocking though

@etraut-openai etraut-openai merged commit 01df50c into main Mar 19, 2026
33 checks passed
@etraut-openai etraut-openai deleted the etraut/threadshellcommand branch March 19, 2026 05:42
@github-actions github-actions bot locked and limited conversation to collaborators Mar 19, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants