Revert tui code so it does not rely on in-process app server (#14899)

PR https://github.com/openai/codex/pull/14512 added an in-process app
server and started to wire up the tui to use it. We were originally
planning to modify the `tui` code in place, converting it to use the app
server a bit at a time using a hybrid adapter. We've since decided to
create an entirely new parallel `tui_app_server` implementation and do
the conversion all at once but retain the existing `tui` while we work
the bugs out of the new implementation.

This PR undoes the changes to the `tui` made in the PR #14512 and
restores the old initialization to its previous state. This allows us to
modify the `tui_app_server` without the risk of regressing the old `tui`
code. For example, we can start to remove support for all legacy core
events, like the ones that PR https://github.com/openai/codex/pull/14892
needed to ignore.

Testing:
* I manually verified that the old `tui` starts and shuts down without a
problem.
This commit is contained in:
Eric Traut
2026-03-17 00:56:32 -06:00
committed by GitHub
parent 57f865c069
commit d37dcca7e0
5 changed files with 18 additions and 253 deletions

View File

@@ -7,10 +7,6 @@ use additional_dirs::add_dir_warning_message;
use app::App;
pub use app::AppExitInfo;
pub use app::ExitReason;
use codex_app_server_client::DEFAULT_IN_PROCESS_CHANNEL_CAPACITY;
use codex_app_server_client::InProcessAppServerClient;
use codex_app_server_client::InProcessClientStartArgs;
use codex_app_server_protocol::ConfigWarningNotification;
use codex_cloud_requirements::cloud_requirements_loader;
use codex_core::AuthManager;
use codex_core::CodexAuth;
@@ -50,15 +46,12 @@ use codex_state::log_db;
use codex_utils_absolute_path::AbsolutePathBuf;
use codex_utils_oss::ensure_oss_provider_ready;
use codex_utils_oss::get_default_model_for_oss_provider;
use color_eyre::eyre::WrapErr;
use cwd_prompt::CwdPromptAction;
use cwd_prompt::CwdPromptOutcome;
use cwd_prompt::CwdSelection;
use std::fs::OpenOptions;
use std::future::Future;
use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
use tracing::error;
use tracing_appender::non_blocking;
use tracing_subscriber::EnvFilter;
@@ -246,74 +239,10 @@ pub use public_widgets::composer_input::ComposerAction;
pub use public_widgets::composer_input::ComposerInput;
// (tests access modules directly within the crate)
async fn start_embedded_app_server(
arg0_paths: Arg0DispatchPaths,
config: Config,
cli_kv_overrides: Vec<(String, toml::Value)>,
loader_overrides: LoaderOverrides,
cloud_requirements: CloudRequirementsLoader,
feedback: codex_feedback::CodexFeedback,
) -> color_eyre::Result<InProcessAppServerClient> {
start_embedded_app_server_with(
arg0_paths,
config,
cli_kv_overrides,
loader_overrides,
cloud_requirements,
feedback,
InProcessAppServerClient::start,
)
.await
}
async fn start_embedded_app_server_with<F, Fut>(
arg0_paths: Arg0DispatchPaths,
config: Config,
cli_kv_overrides: Vec<(String, toml::Value)>,
loader_overrides: LoaderOverrides,
cloud_requirements: CloudRequirementsLoader,
feedback: codex_feedback::CodexFeedback,
start_client: F,
) -> color_eyre::Result<InProcessAppServerClient>
where
F: FnOnce(InProcessClientStartArgs) -> Fut,
Fut: Future<Output = std::io::Result<InProcessAppServerClient>>,
{
let config_warnings = config
.startup_warnings
.iter()
.map(|warning| ConfigWarningNotification {
summary: warning.clone(),
details: None,
path: None,
range: None,
})
.collect();
let client = start_client(InProcessClientStartArgs {
arg0_paths,
config: Arc::new(config),
cli_overrides: cli_kv_overrides,
loader_overrides,
cloud_requirements,
feedback,
config_warnings,
session_source: codex_protocol::protocol::SessionSource::Cli,
enable_codex_api_key_env: false,
client_name: "codex-tui".to_string(),
client_version: env!("CARGO_PKG_VERSION").to_string(),
experimental_api: true,
opt_out_notification_methods: Vec::new(),
channel_capacity: DEFAULT_IN_PROCESS_CHANNEL_CAPACITY,
})
.await
.wrap_err("failed to start embedded app server")?;
Ok(client)
}
pub async fn run_main(
mut cli: Cli,
arg0_paths: Arg0DispatchPaths,
loader_overrides: LoaderOverrides,
_loader_overrides: LoaderOverrides,
) -> std::io::Result<AppExitInfo> {
let (sandbox_mode, approval_policy) = if cli.full_auto {
(
@@ -611,8 +540,6 @@ pub async fn run_main(
run_ratatui_app(
cli,
arg0_paths,
loader_overrides,
config,
overrides,
cli_kv_overrides,
@@ -626,8 +553,6 @@ pub async fn run_main(
#[allow(clippy::too_many_arguments)]
async fn run_ratatui_app(
cli: Cli,
arg0_paths: Arg0DispatchPaths,
loader_overrides: LoaderOverrides,
initial_config: Config,
overrides: ConfigOverrides,
cli_kv_overrides: Vec<(String, toml::Value)>,
@@ -1025,27 +950,10 @@ async fn run_ratatui_app(
let use_alt_screen = determine_alt_screen_mode(no_alt_screen, config.tui_alternate_screen);
tui.set_alt_screen_enabled(use_alt_screen);
let app_server = match start_embedded_app_server(
arg0_paths,
config.clone(),
cli_kv_overrides.clone(),
loader_overrides,
cloud_requirements.clone(),
feedback.clone(),
)
.await
{
Ok(app_server) => app_server,
Err(err) => {
restore();
session_log::log_session_end();
return Err(err);
}
};
let app_result = App::run(
&mut tui,
app_server,
auth_manager,
config,
cli_kv_overrides.clone(),
overrides.clone(),
@@ -1328,20 +1236,6 @@ mod tests {
.await
}
async fn start_test_embedded_app_server(
config: Config,
) -> color_eyre::Result<InProcessAppServerClient> {
start_embedded_app_server(
Arg0DispatchPaths::default(),
config,
Vec::new(),
LoaderOverrides::default(),
CloudRequirementsLoader::default(),
codex_feedback::CodexFeedback::new(),
)
.await
}
#[tokio::test]
#[serial]
async fn windows_shows_trust_prompt_without_sandbox() -> std::io::Result<()> {
@@ -1358,51 +1252,6 @@ mod tests {
Ok(())
}
#[tokio::test]
async fn embedded_app_server_exposes_client_manager_accessors() -> color_eyre::Result<()> {
let temp_dir = TempDir::new()?;
let config = build_config(&temp_dir).await?;
let app_server = start_test_embedded_app_server(config).await?;
assert!(Arc::ptr_eq(
&app_server.auth_manager(),
&app_server.auth_manager()
));
assert!(Arc::ptr_eq(
&app_server.thread_manager(),
&app_server.thread_manager()
));
app_server.shutdown().await?;
Ok(())
}
#[tokio::test]
async fn embedded_app_server_start_failure_is_returned() -> color_eyre::Result<()> {
let temp_dir = TempDir::new()?;
let config = build_config(&temp_dir).await?;
let result = start_embedded_app_server_with(
Arg0DispatchPaths::default(),
config,
Vec::new(),
LoaderOverrides::default(),
CloudRequirementsLoader::default(),
codex_feedback::CodexFeedback::new(),
|_args| async { Err(std::io::Error::other("boom")) },
)
.await;
let err = match result {
Ok(_) => panic!("startup failure should be returned"),
Err(err) => err,
};
assert!(
err.to_string()
.contains("failed to start embedded app server"),
"error should preserve the embedded app server startup context"
);
Ok(())
}
#[tokio::test]
#[serial]
async fn windows_shows_trust_prompt_with_sandbox() -> std::io::Result<()> {