mirror of
https://github.com/openai/codex.git
synced 2026-02-01 22:47:52 +00:00
Compare commits
4 Commits
1271d450b1
...
codex/refa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0efd420071 | ||
|
|
b81cb7ceb3 | ||
|
|
c7a3428986 | ||
|
|
d609dfa2fc |
@@ -1,28 +1,28 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use codex_protocol::models::ShellToolCallParams;
|
||||
use codex_protocol::user_input::UserInput;
|
||||
use tokio::sync::Mutex;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use tracing::error;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::codex::TurnContext;
|
||||
use crate::exec::SandboxType;
|
||||
use crate::exec::StdoutStream;
|
||||
use crate::exec::execute_exec_env;
|
||||
use crate::exec_env::create_env;
|
||||
use crate::protocol::EventMsg;
|
||||
use crate::protocol::TaskStartedEvent;
|
||||
use crate::sandboxing::SandboxManager;
|
||||
use crate::state::TaskKind;
|
||||
use crate::tools::context::ToolPayload;
|
||||
use crate::tools::parallel::ToolCallRuntime;
|
||||
use crate::tools::router::ToolCall;
|
||||
use crate::tools::router::ToolRouter;
|
||||
use crate::turn_diff_tracker::TurnDiffTracker;
|
||||
use crate::tools::events::ToolEmitter;
|
||||
use crate::tools::events::ToolEventCtx;
|
||||
use crate::tools::runtimes::build_command_spec;
|
||||
use crate::tools::sandboxing::ToolError;
|
||||
|
||||
use super::SessionTask;
|
||||
use super::SessionTaskContext;
|
||||
|
||||
const USER_SHELL_TOOL_NAME: &str = "local_shell";
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct UserShellCommandTask {
|
||||
command: String,
|
||||
@@ -78,34 +78,75 @@ impl SessionTask for UserShellCommandTask {
|
||||
}
|
||||
};
|
||||
|
||||
let params = ShellToolCallParams {
|
||||
command: shell_invocation,
|
||||
workdir: None,
|
||||
timeout_ms: None,
|
||||
with_escalated_permissions: None,
|
||||
justification: None,
|
||||
if cancellation_token.is_cancelled() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let call_id = Uuid::new_v4().to_string();
|
||||
let emitter = ToolEmitter::shell(shell_invocation.clone(), turn_context.cwd.clone(), true);
|
||||
let event_ctx = ToolEventCtx::new(session.as_ref(), turn_context.as_ref(), &call_id, None);
|
||||
emitter.begin(event_ctx).await;
|
||||
|
||||
let env = create_env(&turn_context.shell_environment_policy);
|
||||
let spec = match build_command_spec(
|
||||
&shell_invocation,
|
||||
&turn_context.cwd,
|
||||
&env,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
) {
|
||||
Ok(spec) => spec,
|
||||
Err(err) => {
|
||||
let event_ctx =
|
||||
ToolEventCtx::new(session.as_ref(), turn_context.as_ref(), &call_id, None);
|
||||
if let Err(finish_err) = emitter.finish(event_ctx, Err(err)).await {
|
||||
error!(?finish_err, "user shell command failed: {finish_err:?}");
|
||||
}
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
let tool_call = ToolCall {
|
||||
tool_name: USER_SHELL_TOOL_NAME.to_string(),
|
||||
call_id: Uuid::new_v4().to_string(),
|
||||
payload: ToolPayload::LocalShell { params },
|
||||
let manager = SandboxManager::new();
|
||||
let exec_env = match manager.transform(
|
||||
&spec,
|
||||
&turn_context.sandbox_policy,
|
||||
SandboxType::None,
|
||||
&turn_context.cwd,
|
||||
turn_context.codex_linux_sandbox_exe.as_ref(),
|
||||
) {
|
||||
Ok(env) => env,
|
||||
Err(err) => {
|
||||
let event_ctx =
|
||||
ToolEventCtx::new(session.as_ref(), turn_context.as_ref(), &call_id, None);
|
||||
let tool_error = ToolError::Codex(err.into());
|
||||
if let Err(finish_err) = emitter.finish(event_ctx, Err(tool_error)).await {
|
||||
error!(?finish_err, "user shell command failed: {finish_err:?}");
|
||||
}
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
let router = Arc::new(ToolRouter::from_config(&turn_context.tools_config, None));
|
||||
let tracker = Arc::new(Mutex::new(TurnDiffTracker::new()));
|
||||
let runtime = ToolCallRuntime::new(
|
||||
Arc::clone(&router),
|
||||
Arc::clone(&session),
|
||||
Arc::clone(&turn_context),
|
||||
Arc::clone(&tracker),
|
||||
);
|
||||
let stdout_stream = StdoutStream {
|
||||
sub_id: turn_context.sub_id.clone(),
|
||||
call_id: call_id.clone(),
|
||||
tx_event: session.get_tx_event(),
|
||||
};
|
||||
|
||||
if let Err(err) = runtime
|
||||
.handle_tool_call(tool_call, cancellation_token)
|
||||
.await
|
||||
{
|
||||
error!("user shell command failed: {err:?}");
|
||||
let exec_result = tokio::select! {
|
||||
_ = cancellation_token.cancelled() => None,
|
||||
res = execute_exec_env(exec_env, &turn_context.sandbox_policy, Some(stdout_stream)) => Some(res),
|
||||
};
|
||||
|
||||
if let Some(result) = exec_result {
|
||||
let event_ctx =
|
||||
ToolEventCtx::new(session.as_ref(), turn_context.as_ref(), &call_id, None);
|
||||
if let Err(err) = emitter
|
||||
.finish(event_ctx, result.map_err(ToolError::Codex))
|
||||
.await
|
||||
{
|
||||
error!(?err, "user shell command failed: {err:?}");
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ pub enum ToolPayload {
|
||||
},
|
||||
LocalShell {
|
||||
params: ShellToolCallParams,
|
||||
is_user_shell_command: bool,
|
||||
},
|
||||
UnifiedExec {
|
||||
arguments: String,
|
||||
@@ -56,7 +57,7 @@ impl ToolPayload {
|
||||
match self {
|
||||
ToolPayload::Function { arguments } => Cow::Borrowed(arguments),
|
||||
ToolPayload::Custom { input } => Cow::Borrowed(input),
|
||||
ToolPayload::LocalShell { params } => Cow::Owned(params.command.join(" ")),
|
||||
ToolPayload::LocalShell { params, .. } => Cow::Owned(params.command.join(" ")),
|
||||
ToolPayload::UnifiedExec { arguments } => Cow::Borrowed(arguments),
|
||||
ToolPayload::Mcp { raw_arguments, .. } => Cow::Borrowed(raw_arguments),
|
||||
}
|
||||
|
||||
@@ -82,7 +82,10 @@ impl ToolHandler for ShellHandler {
|
||||
)
|
||||
.await
|
||||
}
|
||||
ToolPayload::LocalShell { params } => {
|
||||
ToolPayload::LocalShell {
|
||||
params,
|
||||
is_user_shell_command,
|
||||
} => {
|
||||
let exec_params = Self::to_exec_params(params, turn.as_ref());
|
||||
Self::run_exec_like(
|
||||
tool_name.as_str(),
|
||||
@@ -91,7 +94,7 @@ impl ToolHandler for ShellHandler {
|
||||
turn,
|
||||
tracker,
|
||||
call_id,
|
||||
true,
|
||||
is_user_shell_command,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@@ -219,6 +222,7 @@ impl ShellHandler {
|
||||
env: exec_params.env.clone(),
|
||||
with_escalated_permissions: exec_params.with_escalated_permissions,
|
||||
justification: exec_params.justification.clone(),
|
||||
is_user_shell_command,
|
||||
};
|
||||
let mut orchestrator = ToolOrchestrator::new();
|
||||
let mut runtime = ShellRuntime::new();
|
||||
|
||||
@@ -120,7 +120,10 @@ impl ToolRouter {
|
||||
Ok(Some(ToolCall {
|
||||
tool_name: "local_shell".to_string(),
|
||||
call_id,
|
||||
payload: ToolPayload::LocalShell { params },
|
||||
payload: ToolPayload::LocalShell {
|
||||
params,
|
||||
is_user_shell_command: false,
|
||||
},
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ pub struct ShellRequest {
|
||||
pub env: std::collections::HashMap<String, String>,
|
||||
pub with_escalated_permissions: Option<bool>,
|
||||
pub justification: Option<String>,
|
||||
pub is_user_shell_command: bool,
|
||||
}
|
||||
|
||||
impl ProvidesSandboxRetryData for ShellRequest {
|
||||
@@ -121,6 +122,9 @@ impl Approvable<ShellRequest> for ShellRuntime {
|
||||
policy: AskForApproval,
|
||||
sandbox_policy: &SandboxPolicy,
|
||||
) -> bool {
|
||||
if req.is_user_shell_command {
|
||||
return false;
|
||||
}
|
||||
if is_known_safe_command(&req.command) {
|
||||
return false;
|
||||
}
|
||||
@@ -146,7 +150,7 @@ impl Approvable<ShellRequest> for ShellRuntime {
|
||||
}
|
||||
|
||||
fn wants_escalated_first_attempt(&self, req: &ShellRequest) -> bool {
|
||||
req.with_escalated_permissions.unwrap_or(false)
|
||||
req.is_user_shell_command || req.with_escalated_permissions.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user