mirror of
https://github.com/openai/codex.git
synced 2026-11-14 21:40:39 +00:00
Support configurable timeouts for thread shell commands (#41384)
## What changed - Add an optional `timeoutMs` parameter to `thread/shellCommand` and propagate it to user shell execution. - Preserve the one-hour default when the parameter is omitted or `null`, allow longer deadlines, and treat `0` as an immediate timeout. - Reject negative or otherwise invalid values before execution. Timing out an auxiliary shell command leaves its active turn running. ## Testing - Cover default, extended, immediate, invalid, standalone, active-turn, and interruption behavior. GitOrigin-RevId: d72f67793d9766b7383f28d30140270a4a76a495
This commit is contained in:
@@ -95,7 +95,12 @@ pub async fn inter_agent_communication(
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn run_user_shell_command(sess: &Arc<Session>, sub_id: String, command: String) {
|
||||
pub async fn run_user_shell_command(
|
||||
sess: &Arc<Session>,
|
||||
sub_id: String,
|
||||
command: String,
|
||||
timeout_ms: Option<u64>,
|
||||
) {
|
||||
if let Some((turn_context, cancellation_token)) =
|
||||
sess.active_turn_context_and_cancellation_token().await
|
||||
{
|
||||
@@ -105,6 +110,7 @@ pub async fn run_user_shell_command(sess: &Arc<Session>, sub_id: String, command
|
||||
session,
|
||||
turn_context,
|
||||
command,
|
||||
timeout_ms,
|
||||
cancellation_token,
|
||||
UserShellCommandMode::ActiveTurnAuxiliary,
|
||||
)
|
||||
@@ -116,8 +122,12 @@ pub async fn run_user_shell_command(sess: &Arc<Session>, sub_id: String, command
|
||||
let turn_context = sess
|
||||
.new_turn_with_default_settings(sub_id, Default::default())
|
||||
.await;
|
||||
sess.spawn_task(turn_context, Vec::new(), UserShellCommandTask::new(command))
|
||||
.await;
|
||||
sess.spawn_task(
|
||||
turn_context,
|
||||
Vec::new(),
|
||||
UserShellCommandTask::new(command, timeout_ms),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn resolve_elicitation(
|
||||
@@ -675,8 +685,11 @@ pub(super) async fn submission_loop(
|
||||
set_thread_memory_mode(&sess, sub.id.clone(), mode).await;
|
||||
false
|
||||
}
|
||||
Op::RunUserShellCommand { command } => {
|
||||
run_user_shell_command(&sess, sub.id.clone(), command).await;
|
||||
Op::RunUserShellCommand {
|
||||
command,
|
||||
timeout_ms,
|
||||
} => {
|
||||
run_user_shell_command(&sess, sub.id.clone(), command, timeout_ms).await;
|
||||
false
|
||||
}
|
||||
Op::ResolveElicitation {
|
||||
|
||||
@@ -1549,6 +1549,7 @@ async fn user_shell_commands_do_not_inherit_managed_network_proxy() -> anyhow::R
|
||||
Arc::clone(&session),
|
||||
turn_context,
|
||||
command,
|
||||
/*timeout_ms*/ None,
|
||||
CancellationToken::new(),
|
||||
UserShellCommandMode::StandaloneTurn,
|
||||
)
|
||||
@@ -1583,6 +1584,7 @@ async fn user_shell_commands_remain_login_shells_when_model_login_shells_are_dis
|
||||
Arc::clone(&session),
|
||||
turn_context,
|
||||
command,
|
||||
/*timeout_ms*/ None,
|
||||
CancellationToken::new(),
|
||||
UserShellCommandMode::StandaloneTurn,
|
||||
)
|
||||
@@ -10568,8 +10570,13 @@ async fn run_user_shell_command_does_not_set_reference_context_item() {
|
||||
state.set_reference_context_item(/*item*/ None);
|
||||
}
|
||||
|
||||
handlers::run_user_shell_command(&session, "sub-id".to_string(), "echo shell".to_string())
|
||||
.await;
|
||||
handlers::run_user_shell_command(
|
||||
&session,
|
||||
"sub-id".to_string(),
|
||||
"echo shell".to_string(),
|
||||
/*timeout_ms*/ None,
|
||||
)
|
||||
.await;
|
||||
|
||||
let deadline = StdDuration::from_secs(15);
|
||||
let start = std::time::Instant::now();
|
||||
|
||||
@@ -61,11 +61,15 @@ pub(crate) enum UserShellCommandMode {
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct UserShellCommandTask {
|
||||
command: String,
|
||||
timeout_ms: Option<u64>,
|
||||
}
|
||||
|
||||
impl UserShellCommandTask {
|
||||
pub(crate) fn new(command: String) -> Self {
|
||||
Self { command }
|
||||
pub(crate) fn new(command: String, timeout_ms: Option<u64>) -> Self {
|
||||
Self {
|
||||
command,
|
||||
timeout_ms,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,6 +93,7 @@ impl SessionTask for UserShellCommandTask {
|
||||
session,
|
||||
turn_context,
|
||||
self.command.clone(),
|
||||
self.timeout_ms,
|
||||
cancellation_token,
|
||||
UserShellCommandMode::StandaloneTurn,
|
||||
)
|
||||
@@ -101,6 +106,7 @@ pub(crate) async fn execute_user_shell_command(
|
||||
session: Arc<Session>,
|
||||
turn_context: Arc<TurnContext>,
|
||||
command: String,
|
||||
timeout_ms: Option<u64>,
|
||||
cancellation_token: CancellationToken,
|
||||
mode: UserShellCommandMode,
|
||||
) {
|
||||
@@ -212,9 +218,7 @@ pub(crate) async fn execute_user_shell_command(
|
||||
// inherit a managed proxy from the surrounding session or turn.
|
||||
network: None,
|
||||
network_environment_id: None,
|
||||
// TODO(zhao-oai): Now that we have ExecExpiration::Cancellation, we
|
||||
// should use that instead of an "arbitrarily large" timeout here.
|
||||
expiration: USER_SHELL_TIMEOUT_MS.into(),
|
||||
expiration: timeout_ms.unwrap_or(USER_SHELL_TIMEOUT_MS).into(),
|
||||
capture_policy: ExecCapturePolicy::ShellTool,
|
||||
sandbox: SandboxType::None,
|
||||
windows_sandbox_policy_cwd: cwd.clone().into(),
|
||||
|
||||
Reference in New Issue
Block a user