show remote host in exec tui cells

This commit is contained in:
Nathan Liebrecht
2026-04-10 12:57:00 -07:00
parent 6a44fb6309
commit 41e490df30
17 changed files with 239 additions and 43 deletions
+4
View File
@@ -152,6 +152,7 @@ pub(crate) async fn execute_user_shell_command(
cwd: cwd.to_path_buf(),
parsed_cmd: parsed_cmd.clone(),
source: ExecCommandSource::UserShell,
host_id: None,
interaction_input: None,
}),
)
@@ -220,6 +221,7 @@ pub(crate) async fn execute_user_shell_command(
cwd: cwd.to_path_buf(),
parsed_cmd: parsed_cmd.clone(),
source: ExecCommandSource::UserShell,
host_id: None,
interaction_input: None,
stdout: String::new(),
stderr: aborted_message.clone(),
@@ -244,6 +246,7 @@ pub(crate) async fn execute_user_shell_command(
cwd: cwd.to_path_buf(),
parsed_cmd: parsed_cmd.clone(),
source: ExecCommandSource::UserShell,
host_id: None,
interaction_input: None,
stdout: output.stdout.text.clone(),
stderr: output.stderr.text.clone(),
@@ -288,6 +291,7 @@ pub(crate) async fn execute_user_shell_command(
cwd: cwd.to_path_buf(),
parsed_cmd,
source: ExecCommandSource::UserShell,
host_id: None,
interaction_input: None,
stdout: exec_output.stdout.text.clone(),
stderr: exec_output.stderr.text.clone(),
+19 -25
View File
@@ -61,27 +61,20 @@ pub(crate) enum ToolEventFailure {
Rejected(String),
}
pub(crate) async fn emit_exec_command_begin(
ctx: ToolEventCtx<'_>,
command: &[String],
cwd: &Path,
parsed_cmd: &[ParsedCommand],
source: ExecCommandSource,
interaction_input: Option<String>,
process_id: Option<&str>,
) {
async fn emit_exec_command_begin(ctx: ToolEventCtx<'_>, exec_input: &ExecCommandInput<'_>) {
ctx.session
.send_event(
ctx.turn,
EventMsg::ExecCommandBegin(ExecCommandBeginEvent {
call_id: ctx.call_id.to_string(),
process_id: process_id.map(str::to_owned),
process_id: exec_input.process_id.map(str::to_owned),
turn_id: ctx.turn.sub_id.clone(),
command: command.to_vec(),
cwd: cwd.to_path_buf(),
parsed_cmd: parsed_cmd.to_vec(),
source,
interaction_input,
command: exec_input.command.to_vec(),
cwd: exec_input.cwd.to_path_buf(),
parsed_cmd: exec_input.parsed_cmd.to_vec(),
source: exec_input.source,
host_id: exec_input.host_id.map(str::to_owned),
interaction_input: exec_input.interaction_input.map(str::to_owned),
}),
)
.await;
@@ -105,6 +98,7 @@ pub(crate) enum ToolEmitter {
source: ExecCommandSource,
parsed_cmd: Vec<ParsedCommand>,
process_id: Option<String>,
host_id: Option<String>,
},
}
@@ -137,6 +131,7 @@ impl ToolEmitter {
cwd: PathBuf,
source: ExecCommandSource,
process_id: Option<String>,
host_id: Option<String>,
) -> Self {
let parsed_cmd = parse_command(command);
Self::UnifiedExec {
@@ -145,6 +140,7 @@ impl ToolEmitter {
source,
parsed_cmd,
process_id,
host_id,
}
}
@@ -169,6 +165,7 @@ impl ToolEmitter {
*source,
/*interaction_input*/ None,
/*process_id*/ None,
/*host_id*/ None,
),
stage,
)
@@ -266,6 +263,7 @@ impl ToolEmitter {
source,
parsed_cmd,
process_id,
host_id,
},
stage,
) => {
@@ -278,6 +276,7 @@ impl ToolEmitter {
*source,
/*interaction_input*/ None,
process_id.as_deref(),
host_id.as_deref(),
),
stage,
)
@@ -370,6 +369,7 @@ struct ExecCommandInput<'a> {
source: ExecCommandSource,
interaction_input: Option<&'a str>,
process_id: Option<&'a str>,
host_id: Option<&'a str>,
}
impl<'a> ExecCommandInput<'a> {
@@ -380,6 +380,7 @@ impl<'a> ExecCommandInput<'a> {
source: ExecCommandSource,
interaction_input: Option<&'a str>,
process_id: Option<&'a str>,
host_id: Option<&'a str>,
) -> Self {
Self {
command,
@@ -388,6 +389,7 @@ impl<'a> ExecCommandInput<'a> {
source,
interaction_input,
process_id,
host_id,
}
}
}
@@ -409,16 +411,7 @@ async fn emit_exec_stage(
) {
match stage {
ToolEventStage::Begin => {
emit_exec_command_begin(
ctx,
exec_input.command,
exec_input.cwd,
exec_input.parsed_cmd,
exec_input.source,
exec_input.interaction_input.map(str::to_owned),
exec_input.process_id,
)
.await;
emit_exec_command_begin(ctx, &exec_input).await;
}
ToolEventStage::Success(output)
| ToolEventStage::Failure(ToolEventFailure::Output(output)) => {
@@ -482,6 +475,7 @@ async fn emit_exec_end(
cwd: exec_input.cwd.to_path_buf(),
parsed_cmd: exec_input.parsed_cmd.to_vec(),
source: exec_input.source,
host_id: exec_input.host_id.map(str::to_owned),
interaction_input: exec_input.interaction_input.map(str::to_owned),
stdout: exec_result.stdout,
stderr: exec_result.stderr,
@@ -185,12 +185,13 @@ impl ToolHandler for UnifiedExecHandler {
"exec_command" => {
let cwd = resolve_workdir_base_path(&arguments, &context.turn.cwd)?;
let args: ExecCommandArgs = parse_arguments_with_base_path(&arguments, &cwd)?;
let environment = resolve_exec_environment(
let resolved_environment = resolve_exec_environment(
session.as_ref(),
turn.as_ref(),
args.host_id.as_deref(),
)
.await?;
let environment = resolved_environment.environment;
let default_host_cwd = if environment.is_remote() && args.workdir.is_none() {
environment
.default_cwd()
@@ -232,7 +233,7 @@ impl ToolHandler for UnifiedExecHandler {
)
.map_err(FunctionCallError::RespondToModel)?;
let command_for_display = codex_shell_command::parse_command::shlex_join(&command);
let request_host_id = args.host_id.clone();
let request_host_id = resolved_environment.host_id;
let ExecCommandArgs {
workdir,
@@ -409,11 +410,16 @@ fn emit_unified_exec_tty_metric(session_telemetry: &SessionTelemetry, tty: bool)
);
}
struct ResolvedExecEnvironment {
environment: Arc<codex_exec_server::Environment>,
host_id: Option<String>,
}
async fn resolve_exec_environment(
session: &crate::codex::Session,
turn: &crate::codex::TurnContext,
host_id: Option<&str>,
) -> Result<Arc<codex_exec_server::Environment>, FunctionCallError> {
) -> Result<ResolvedExecEnvironment, FunctionCallError> {
let environment = match host_id {
Some(host_id) => session
.services
@@ -428,8 +434,28 @@ async fn resolve_exec_environment(
None => turn.environment.clone(),
};
environment.ok_or_else(|| {
let environment = environment.ok_or_else(|| {
FunctionCallError::RespondToModel("unified exec is unavailable in this session".to_string())
})?;
let host_id = if environment.is_remote() {
Some(match host_id {
Some(host_id) => host_id.to_string(),
None => {
let default_host_id = session.services.environment_manager.default_host_id();
if default_host_id == codex_exec_server::LOCAL_HOST_ID {
"remote".to_string()
} else {
default_host_id
}
}
})
} else {
None
};
Ok(ResolvedExecEnvironment {
environment,
host_id,
})
}
@@ -110,6 +110,7 @@ pub(crate) fn spawn_exit_watcher(
turn_ref: Arc<TurnContext>,
call_id: String,
command: Vec<String>,
host_id: Option<String>,
cwd: PathBuf,
process_id: i32,
transcript: Arc<Mutex<HeadTailBuffer>>,
@@ -129,6 +130,7 @@ pub(crate) fn spawn_exit_watcher(
turn_ref,
call_id,
command,
host_id,
cwd,
Some(process_id.to_string()),
transcript,
@@ -143,6 +145,7 @@ pub(crate) fn spawn_exit_watcher(
turn_ref,
call_id,
command,
host_id,
cwd,
Some(process_id.to_string()),
transcript,
@@ -196,6 +199,7 @@ pub(crate) async fn emit_exec_end_for_unified_exec(
turn_ref: Arc<TurnContext>,
call_id: String,
command: Vec<String>,
host_id: Option<String>,
cwd: PathBuf,
process_id: Option<String>,
transcript: Arc<Mutex<HeadTailBuffer>>,
@@ -223,6 +227,7 @@ pub(crate) async fn emit_exec_end_for_unified_exec(
cwd,
ExecCommandSource::UnifiedExecStartup,
process_id,
host_id,
);
emitter
.emit(event_ctx, ToolEventStage::Success(output))
@@ -235,6 +240,7 @@ pub(crate) async fn emit_failed_exec_end_for_unified_exec(
turn_ref: Arc<TurnContext>,
call_id: String,
command: Vec<String>,
host_id: Option<String>,
cwd: PathBuf,
process_id: Option<String>,
transcript: Arc<Mutex<HeadTailBuffer>>,
@@ -266,6 +272,7 @@ pub(crate) async fn emit_failed_exec_end_for_unified_exec(
cwd,
ExecCommandSource::UnifiedExecStartup,
process_id,
host_id,
);
emitter
.emit(
@@ -192,6 +192,7 @@ impl UnifiedExecProcessManager {
cwd.to_path_buf(),
ExecCommandSource::UnifiedExecStartup,
Some(request.process_id.to_string()),
request.host_id.clone(),
);
emitter.emit(event_ctx, ToolEventStage::Begin).await;
@@ -208,6 +209,7 @@ impl UnifiedExecProcessManager {
Arc::clone(&process),
context,
&request.command,
request.host_id.clone(),
cwd.clone(),
start,
request.process_id,
@@ -255,6 +257,7 @@ impl UnifiedExecProcessManager {
Arc::clone(&context.turn),
context.call_id.clone(),
request.command.clone(),
request.host_id.clone(),
cwd.to_path_buf(),
Some(request.process_id.to_string()),
Arc::clone(&transcript),
@@ -298,6 +301,7 @@ impl UnifiedExecProcessManager {
Arc::clone(&context.turn),
context.call_id.clone(),
request.command.clone(),
request.host_id.clone(),
cwd.to_path_buf(),
Some(process_id.to_string()),
Arc::clone(&transcript),
@@ -526,6 +530,7 @@ impl UnifiedExecProcessManager {
process: Arc<UnifiedExecProcess>,
context: &UnifiedExecContext,
command: &[String],
host_id: Option<String>,
cwd: AbsolutePathBuf,
started_at: Instant,
process_id: i32,
@@ -572,6 +577,7 @@ impl UnifiedExecProcessManager {
Arc::clone(&context.turn),
context.call_id.clone(),
command.to_vec(),
host_id,
cwd.to_path_buf(),
process_id,
transcript,