|
fn to_exec_params(params: ShellToolCallParams, turn_context: &TurnContext) -> ExecParams { |
|
ExecParams { |
|
command: params.command, |
|
cwd: turn_context.resolve_path(params.workdir.clone()), |
|
timeout_ms: params.timeout_ms, |
|
env: create_env(&turn_context.shell_environment_policy), |
|
with_escalated_permissions: params.with_escalated_permissions, |
|
justification: params.justification, |
|
} |
|
} |
|
|
|
fn parse_container_exec_arguments( |
|
arguments: String, |
|
turn_context: &TurnContext, |
|
_call_id: &str, |
|
) -> Result<ExecParams, FunctionCallError> { |
|
serde_json::from_str::<ShellToolCallParams>(&arguments) |
|
.map(|p| to_exec_params(p, turn_context)) |
|
.map_err(|e| { |
|
FunctionCallError::RespondToModel(format!("failed to parse function arguments: {e:?}")) |
|
}) |
|
} |
|
|
|
pub struct ExecInvokeArgs<'a> { |
|
pub params: ExecParams, |
|
pub sandbox_type: SandboxType, |
|
pub sandbox_policy: &'a SandboxPolicy, |
|
pub sandbox_cwd: &'a Path, |
|
pub codex_linux_sandbox_exe: &'a Option<PathBuf>, |
|
pub stdout_stream: Option<StdoutStream>, |
|
} |
|
|
|
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, |
|
turn_context: &TurnContext, |
|
turn_diff_tracker: &mut TurnDiffTracker, |
|
sub_id: String, |
|
call_id: String, |
|
) -> Result<String, FunctionCallError> { |
|
if params.with_escalated_permissions.unwrap_or(false) |
|
&& !matches!(turn_context.approval_policy, AskForApproval::OnRequest) |
|
{ |
|
return Err(FunctionCallError::RespondToModel(format!( |
|
"approval policy is {policy:?}; reject command — you should not ask for escalated permissions if the approval policy is {policy:?}", |
|
policy = turn_context.approval_policy |
|
))); |
|
} |
|
|
|
// check if this was a patch, and apply it if so |
|
let apply_patch_exec = match maybe_parse_apply_patch_verified(¶ms.command, ¶ms.cwd) { |
|
MaybeApplyPatchVerified::Body(changes) => { |
|
match apply_patch::apply_patch(sess, turn_context, &sub_id, &call_id, changes).await { |
|
InternalApplyPatchInvocation::Output(item) => return item, |
|
InternalApplyPatchInvocation::DelegateToExec(apply_patch_exec) => { |
|
Some(apply_patch_exec) |
|
} |
|
} |
|
} |
|
MaybeApplyPatchVerified::CorrectnessError(parse_error) => { |
|
// It looks like an invocation of `apply_patch`, but we |
|
// could not resolve it into a patch that would apply |
|
// cleanly. Return to model for resample. |
|
return Err(FunctionCallError::RespondToModel(format!( |
|
"error: {parse_error:#?}" |
|
))); |
|
} |
|
MaybeApplyPatchVerified::ShellParseError(error) => { |