Keep TUI preferences editable when execution settings are invalid (#56091)

## Why

Saving a local preference could succeed but fail to apply live because reloading the full configuration also resolved execution settings. An unknown `model_provider`, for example, prevented the preference from taking effect.

## What changed

Reload config-panel preferences from the configuration layer stack into `LocalSettings` without rebuilding execution settings. Preserve CLI overrides, loader overrides, cloud configuration, and the existing choice of working directory.

## Testing

Extend the offline remote-session preference test with an unknown `model_provider` override, verifying that automatic recap and paste detection preferences still persist and apply live.

GitOrigin-RevId: 2377a01c77f3cb978a7ee6cd67c1fe89361131fb
This commit is contained in:
Eric Traut
2026-10-22 05:51:47 +00:00
committed by copyberry
parent 47a1f6bb77
commit c2d5ea52e1
2 changed files with 24 additions and 2 deletions
+22 -2
View File
@@ -4,6 +4,8 @@ use super::*;
use crate::config_panel::ConfigPreference;
use crate::config_panel::ConfigToggle;
use crate::config_update::format_config_error;
use crate::legacy_core::config::load_config_toml_with_layer_stack;
use crate::local_settings::LocalSettings;
impl App {
pub(super) async fn save_config_preference(
@@ -34,8 +36,26 @@ impl App {
} else {
self.chat_widget.config_ref().cwd.to_path_buf()
};
let resolved = match self.rebuild_config_for_cwd(config_cwd).await {
Ok(config) => crate::local_settings::LocalSettings::from(&config),
let resolved = match async {
let cwd = AbsolutePathBuf::relative_to_current_dir(&config_cwd)?;
let bootstrap = load_config_toml_with_layer_stack(
self.local_settings.codex_home.as_path(),
Some(&cwd),
self.cli_kv_overrides.clone(),
codex_config::ConfigLoadOptions {
loader_overrides: self.loader_overrides.clone(),
cloud_config_bundle: self.cloud_config_bundle.clone(),
..Default::default()
},
)
.await?;
LocalSettings::from_bootstrap(&bootstrap, self.local_settings.codex_home.clone())
.map_err(std::io::Error::other)
}
.await
.wrap_err_with(|| format!("Failed to rebuild config for cwd {}", config_cwd.display()))
{
Ok(settings) => settings,
Err(error) => {
self.chat_widget
.refresh_config_panel(
@@ -92,6 +92,8 @@ async fn config_toggle_save_uses_host_config_and_applies_live_while_offline() ->
app.chat_widget = ChatWidget::new_with_app_event(init);
app.local_settings.tui.auto_recap = true;
app.chat_widget.local_settings.tui.auto_recap = true;
// Resolving execution settings would fail, but local preferences remain editable.
app.cli_kv_overrides = vec![("model_provider".into(), "missing-provider".into())];
Box::pin(app.handle_event(
&mut tui,