This commit is contained in:
jimmyfraiture
2025-09-30 11:55:43 +01:00
parent 4656160e31
commit 1d87628d41
4 changed files with 80 additions and 43 deletions
+23 -39
View File
@@ -906,7 +906,11 @@ impl Session {
&self,
turn_diff_tracker: &mut TurnDiffTracker,
begin_ctx: ExecCommandContext,
request: ExecutionRequest,
params: ExecParams,
approval_command: Vec<String>,
mode: ExecutionMode,
stdout_stream: Option<StdoutStream>,
use_shell_profile: bool,
approval_policy: AskForApproval,
) -> Result<ExecToolCallOutput, ExecError> {
let is_apply_patch = begin_ctx.apply_patch.is_some();
@@ -916,6 +920,14 @@ impl Session {
self.on_exec_command_begin(turn_diff_tracker, begin_ctx.clone())
.await;
let request = ExecutionRequest {
params,
approval_command,
mode,
stdout_stream,
use_shell_profile,
};
let result = self
.services
.executor
@@ -1030,7 +1042,7 @@ impl Session {
&self.services.notifier
}
fn user_shell(&self) -> &shell::Shell {
pub(crate) fn user_shell(&self) -> &shell::Shell {
&self.services.user_shell
}
@@ -2508,24 +2520,6 @@ fn parse_container_exec_arguments(
})
}
fn maybe_translate_shell_command(
params: ExecParams,
sess: &Session,
turn_context: &TurnContext,
) -> ExecParams {
let should_translate = matches!(sess.user_shell(), crate::shell::Shell::PowerShell(_))
|| turn_context.shell_environment_policy.use_profile;
if should_translate
&& let Some(command) = sess
.user_shell()
.format_default_shell_invocation(params.command.clone())
{
return ExecParams { command, ..params };
}
params
}
async fn handle_container_exec_with_params(
params: ExecParams,
sess: &Session,
@@ -2590,29 +2584,11 @@ async fn handle_container_exec_with_params(
),
};
let translated_params = maybe_translate_shell_command(params, sess, turn_context);
let stdout_stream = if exec_command_context.apply_patch.is_some() {
None
} else {
Some(StdoutStream {
sub_id: sub_id.clone(),
call_id: call_id.clone(),
tx_event: sess.tx_event.clone(),
})
};
let mode = match apply_patch_exec {
Some(exec) => ExecutionMode::ApplyPatch(exec),
None => ExecutionMode::Shell,
};
let request = ExecutionRequest {
params: translated_params,
approval_command: command_for_display,
mode,
stdout_stream,
};
sess.services.executor.update_environment(
turn_context.sandbox_policy.clone(),
turn_context.cwd.clone(),
@@ -2622,7 +2598,15 @@ async fn handle_container_exec_with_params(
.run_exec_with_events(
turn_diff_tracker,
exec_command_context,
request,
params,
command_for_display,
mode,
Some(StdoutStream {
sub_id: sub_id.clone(), // todo we should not nead the ids
call_id: call_id.clone(),
tx_event: sess.tx_event.clone(),
}),
turn_context.shell_environment_policy.use_profile,
turn_context.approval_policy,
)
.await;
+8
View File
@@ -23,6 +23,10 @@ pub(crate) trait ExecutionBackend: Send + Sync {
// Required for downcasting the apply_patch.
mode: &ExecutionMode,
) -> Result<ExecParams, FunctionCallError>;
fn stream_stdout(&self, _mode: &ExecutionMode) -> bool {
true
}
}
static SHELL_BACKEND: ShellBackend = ShellBackend;
@@ -90,4 +94,8 @@ impl ExecutionBackend for ApplyPatchBackend {
)),
}
}
fn stream_stdout(&self, _mode: &ExecutionMode) -> bool {
false
}
}
+44 -4
View File
@@ -23,6 +23,7 @@ use crate::function_tool::FunctionCallError;
use crate::protocol::AskForApproval;
use crate::protocol::ReviewDecision;
use crate::protocol::SandboxPolicy;
use crate::shell;
#[derive(Clone, Debug)]
pub(crate) struct ExecutorConfig {
@@ -94,8 +95,18 @@ impl Executor {
sub_id: &str,
call_id: &str,
) -> Result<ExecToolCallOutput, ExecError> {
if matches!(request.mode, ExecutionMode::Shell) {
request.params =
maybe_translate_shell_command(request.params, session, request.use_shell_profile);
}
// Step 1: Normalise parameters via the selected backend.
let backend = backend_for_mode(&request.mode);
let stdout_stream = if backend.stream_stdout(&request.mode) {
request.stdout_stream.clone()
} else {
None
};
request.params = backend
.prepare(request.params, &request.mode)
.map_err(ExecError::from)?;
@@ -128,7 +139,7 @@ impl Executor {
request.params.clone(),
sandbox_decision.initial_sandbox,
&config,
request.stdout_stream.clone(),
stdout_stream.clone(),
)
.await;
@@ -140,8 +151,16 @@ impl Executor {
}
Err(CodexErr::Sandbox(error @ SandboxErr::Denied { .. })) => {
return if sandbox_decision.escalate_on_failure {
self.retry_without_sandbox(&request, &config, session, sub_id, call_id, error)
.await
self.retry_without_sandbox(
&request,
&config,
session,
sub_id,
call_id,
stdout_stream.clone(),
error,
)
.await
} else {
Err(ExecError::rejection(format!(
"failed in sandbox {:?} with execution error: {error:?}",
@@ -165,6 +184,7 @@ impl Executor {
session: &Session,
sub_id: &str,
call_id: &str,
stdout_stream: Option<StdoutStream>,
sandbox_error: SandboxErr,
) -> Result<ExecToolCallOutput, ExecError> {
session
@@ -194,7 +214,7 @@ impl Executor {
request.params.clone(),
SandboxType::None,
config,
request.stdout_stream.clone(),
stdout_stream,
)
.await?;
@@ -225,11 +245,31 @@ impl Executor {
}
}
fn maybe_translate_shell_command(
params: ExecParams,
session: &Session,
use_shell_profile: bool,
) -> ExecParams {
let should_translate =
matches!(session.user_shell(), shell::Shell::PowerShell(_)) || use_shell_profile;
if should_translate
&& let Some(command) = session
.user_shell()
.format_default_shell_invocation(params.command.clone())
{
return ExecParams { command, ..params };
}
params
}
pub(crate) struct ExecutionRequest {
pub params: ExecParams,
pub approval_command: Vec<String>,
pub mode: ExecutionMode,
pub stdout_stream: Option<StdoutStream>,
pub use_shell_profile: bool,
}
pub(crate) struct NormalizedExecOutput<'a> {
+5
View File
@@ -196,6 +196,7 @@ mod tests {
approval_command: vec!["apply_patch".into()],
mode: ExecutionMode::ApplyPatch(exec),
stdout_stream: None,
use_shell_profile: false,
};
let decision = select_sandbox(
&request,
@@ -236,6 +237,7 @@ mod tests {
approval_command: vec!["apply_patch".into()],
mode: ExecutionMode::ApplyPatch(exec),
stdout_stream: None,
use_shell_profile: false,
};
let decision = select_sandbox(
&request,
@@ -277,6 +279,7 @@ mod tests {
approval_command: vec!["apply_patch".into()],
mode: ExecutionMode::ApplyPatch(exec),
stdout_stream: None,
use_shell_profile: false,
};
let result = select_sandbox(
&request,
@@ -313,6 +316,7 @@ mod tests {
approval_command: vec!["some-unknown".into()],
mode: ExecutionMode::Shell,
stdout_stream: None,
use_shell_profile: false,
};
let decision = select_sandbox(
&request,
@@ -347,6 +351,7 @@ mod tests {
approval_command: vec!["some-unknown".into()],
mode: ExecutionMode::Shell,
stdout_stream: None,
use_shell_profile: false,
};
let decision = select_sandbox(
&request,