mirror of
https://github.com/openai/codex.git
synced 2026-10-20 17:38:45 +00:00
code-mode: fall back to using in process v8 if we fail to resolve external process (#31899)
## Why Not every Codex distribution currently includes the `codex-code-mode-host` companion binary. Enabling the process-host feature should not make code mode unavailable on those surfaces while packaging support is being completed. ## What changed - Fall back to an in-process code-mode session only when spawning the companion binary returns `io::ErrorKind::NotFound`. - Keep permission, handshake, timeout, and other host failures visible instead of silently falling back. - Store the provider's owned-process/in-process choice as one enum-backed state so later sessions reuse the fallback decision. - Preserve the underlying spawn `io::Error` while retaining the host path in the displayed error. - Update provider, `CodeModeService`, and end-to-end coverage to verify successful fallback execution. ## Test plan - `just test -p codex-code-mode` - `just test -p codex-core missing_process_host`
This commit is contained in:
@@ -1,4 +1,7 @@
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Stdio;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
@@ -46,6 +49,39 @@ mod reader;
|
||||
const IPC_CHANNEL_CAPACITY: usize = 128;
|
||||
const HOST_HANDSHAKE_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
|
||||
pub(super) enum ConnectionError {
|
||||
Spawn {
|
||||
host_program: PathBuf,
|
||||
error: io::Error,
|
||||
},
|
||||
Other(String),
|
||||
}
|
||||
|
||||
impl ConnectionError {
|
||||
pub(super) fn host_program_not_found(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
Self::Spawn { error, .. } if error.kind() == io::ErrorKind::NotFound
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ConnectionError {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Spawn {
|
||||
host_program,
|
||||
error,
|
||||
} => write!(
|
||||
formatter,
|
||||
"failed to spawn code-mode host {}: {error}",
|
||||
host_program.display()
|
||||
),
|
||||
Self::Other(message) => formatter.write_str(message),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct Connection {
|
||||
command_tx: mpsc::Sender<DriverCommand>,
|
||||
execute_claim_tx: mpsc::UnboundedSender<RequestId>,
|
||||
@@ -96,7 +132,7 @@ impl Drop for CallerCancellation {
|
||||
}
|
||||
|
||||
impl Connection {
|
||||
pub(super) async fn spawn(host_program: &Path) -> Result<Self, String> {
|
||||
pub(super) async fn spawn(host_program: &Path) -> Result<Self, ConnectionError> {
|
||||
let mut command = Command::new(host_program);
|
||||
#[cfg(unix)]
|
||||
command.process_group(0);
|
||||
@@ -106,11 +142,9 @@ impl Connection {
|
||||
.stderr(Stdio::piped())
|
||||
.kill_on_drop(true)
|
||||
.spawn()
|
||||
.map_err(|err| {
|
||||
format!(
|
||||
"failed to spawn code-mode host {}: {err}",
|
||||
host_program.display()
|
||||
)
|
||||
.map_err(|error| ConnectionError::Spawn {
|
||||
host_program: host_program.to_path_buf(),
|
||||
error,
|
||||
})?;
|
||||
|
||||
if let Some(stderr) = child.stderr.take() {
|
||||
@@ -132,11 +166,11 @@ impl Connection {
|
||||
let stdin = child
|
||||
.stdin
|
||||
.take()
|
||||
.ok_or_else(|| "spawned code-mode host has no stdin".to_string())?;
|
||||
.ok_or_else(|| ConnectionError::Other("spawned code-mode host has no stdin".into()))?;
|
||||
let stdout = child
|
||||
.stdout
|
||||
.take()
|
||||
.ok_or_else(|| "spawned code-mode host has no stdout".to_string())?;
|
||||
.ok_or_else(|| ConnectionError::Other("spawned code-mode host has no stdout".into()))?;
|
||||
let mut reader = FramedReader::new(stdout);
|
||||
let mut writer = FramedWriter::new(stdin);
|
||||
let handshake = async {
|
||||
@@ -174,12 +208,14 @@ impl Connection {
|
||||
Ok(result) => result,
|
||||
Err(_) => {
|
||||
kill_and_reap(&mut child).await;
|
||||
return Err("timed out negotiating with the code-mode host".to_string());
|
||||
return Err(ConnectionError::Other(
|
||||
"timed out negotiating with the code-mode host".into(),
|
||||
));
|
||||
}
|
||||
};
|
||||
if let Err(err) = handshake_result {
|
||||
kill_and_reap(&mut child).await;
|
||||
return Err(err);
|
||||
return Err(ConnectionError::Other(err));
|
||||
}
|
||||
|
||||
let (command_tx, command_rx) = mpsc::channel(IPC_CHANNEL_CAPACITY);
|
||||
|
||||
Reference in New Issue
Block a user