mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
[1 of 4] tui: route primary settings writes through app server (#22913)
## Why The TUI can run against a remote app server, but several high-traffic settings still persisted by editing the local config file. That sends remote sessions' preference writes to the wrong machine and lets local disk state drift from the app-server-owned config. This is **[1 of 4]** in a stacked series that moves TUI-owned config mutations onto app-server APIs. ## What changed - Added a small TUI helper for typed app-server config writes. - Routed primary interactive preference writes through `config/batchWrite`. - Preserved existing profile scoping for settings that already support `profiles.<profile>.*` overrides. ## Config keys affected - `model` - `model_reasoning_effort` - `personality` - `service_tier` - `plan_mode_reasoning_effort` - `approvals_reviewer` - `notice.fast_default_opt_out` - Profile-scoped equivalents under `profiles.<profile>.*` ## Suggested manual validation - Connect the TUI to a remote app server, change `model` and `model_reasoning_effort`, reconnect, and confirm the remote config retained both values while the local `config.toml` did not change. - Change `personality`, `plan_mode_reasoning_effort`, and the explicit auto-review selection, then reconnect and confirm those choices persist through the app server. - Clear the service tier back to default and confirm `service_tier` is cleared while `notice.fast_default_opt_out = true` is persisted remotely. - Repeat one setting change with an active profile and confirm the write lands under `profiles.<profile>.*`. ## Stack 1. [#22913](https://github.com/openai/codex/pull/22913) `[1 of 4]` primary settings writes 2. [#22914](https://github.com/openai/codex/pull/22914) `[2 of 4]` app and skill enablement 3. [#22915](https://github.com/openai/codex/pull/22915) `[3 of 4]` feature and memory toggles 4. [#22916](https://github.com/openai/codex/pull/22916) `[4 of 4]` startup and onboarding bookkeeping
This commit is contained in:
@@ -1183,11 +1183,15 @@ impl App {
|
||||
}
|
||||
AppEvent::PersistModelSelection { model, effort } => {
|
||||
let profile = self.active_profile.as_deref();
|
||||
match ConfigEditsBuilder::for_config(&self.config)
|
||||
.with_profile(profile)
|
||||
.set_model(Some(model.as_str()), effort)
|
||||
.apply()
|
||||
.await
|
||||
match crate::config_update::write_config_batch(
|
||||
app_server.request_handle(),
|
||||
crate::config_update::build_model_selection_edits(
|
||||
profile,
|
||||
model.as_str(),
|
||||
effort,
|
||||
),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(()) => {
|
||||
let effort_label = effort
|
||||
@@ -1261,11 +1265,14 @@ impl App {
|
||||
}
|
||||
AppEvent::PersistPersonalitySelection { personality } => {
|
||||
let profile = self.active_profile.as_deref();
|
||||
match ConfigEditsBuilder::for_config(&self.config)
|
||||
.with_profile(profile)
|
||||
.set_personality(Some(personality))
|
||||
.apply()
|
||||
.await
|
||||
match crate::config_update::write_config_batch(
|
||||
app_server.request_handle(),
|
||||
vec![crate::config_update::replace_config_value(
|
||||
crate::config_update::profile_scoped_key_path(profile, "personality"),
|
||||
serde_json::json!(personality.to_string()),
|
||||
)],
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(()) => {
|
||||
let label = Self::personality_label(personality);
|
||||
@@ -1298,14 +1305,16 @@ impl App {
|
||||
self.refresh_status_line();
|
||||
let profile = self.active_profile.as_deref();
|
||||
self.config.service_tier = service_tier.clone();
|
||||
let mut edits = ConfigEditsBuilder::for_config(&self.config)
|
||||
.with_profile(profile)
|
||||
.set_service_tier(service_tier.clone());
|
||||
let edits = crate::config_update::build_service_tier_selection_edits(
|
||||
profile,
|
||||
service_tier.as_deref(),
|
||||
);
|
||||
if service_tier.is_none() {
|
||||
self.config.notices.fast_default_opt_out = Some(true);
|
||||
edits = edits.set_fast_default_opt_out(/*opted_out*/ true);
|
||||
}
|
||||
match edits.apply().await {
|
||||
match crate::config_update::write_config_batch(app_server.request_handle(), edits)
|
||||
.await
|
||||
{
|
||||
Ok(()) => {
|
||||
let mut message = if let Some(service_tier) = service_tier {
|
||||
format!("Service tier set to {service_tier}")
|
||||
@@ -1476,23 +1485,17 @@ impl App {
|
||||
self.sync_active_thread_permission_settings_to_cached_session()
|
||||
.await;
|
||||
let profile = self.active_profile.as_deref();
|
||||
let segments = if let Some(profile) = profile {
|
||||
vec![
|
||||
"profiles".to_string(),
|
||||
profile.to_string(),
|
||||
"approvals_reviewer".to_string(),
|
||||
]
|
||||
} else {
|
||||
vec!["approvals_reviewer".to_string()]
|
||||
};
|
||||
if let Err(err) = ConfigEditsBuilder::for_config(&self.config)
|
||||
.with_profile(profile)
|
||||
.with_edits([ConfigEdit::SetPath {
|
||||
segments,
|
||||
value: policy.to_string().into(),
|
||||
}])
|
||||
.apply()
|
||||
.await
|
||||
if let Err(err) = crate::config_update::write_config_batch(
|
||||
app_server.request_handle(),
|
||||
vec![crate::config_update::replace_config_value(
|
||||
crate::config_update::profile_scoped_key_path(
|
||||
profile,
|
||||
"approvals_reviewer",
|
||||
),
|
||||
serde_json::json!(policy.to_string()),
|
||||
)],
|
||||
)
|
||||
.await
|
||||
{
|
||||
tracing::error!(
|
||||
error = %err,
|
||||
@@ -1583,27 +1586,23 @@ impl App {
|
||||
}
|
||||
AppEvent::PersistPlanModeReasoningEffort(effort) => {
|
||||
let profile = self.active_profile.as_deref();
|
||||
let segments = if let Some(profile) = profile {
|
||||
vec![
|
||||
"profiles".to_string(),
|
||||
profile.to_string(),
|
||||
"plan_mode_reasoning_effort".to_string(),
|
||||
]
|
||||
} else {
|
||||
vec!["plan_mode_reasoning_effort".to_string()]
|
||||
};
|
||||
let key_path = crate::config_update::profile_scoped_key_path(
|
||||
profile,
|
||||
"plan_mode_reasoning_effort",
|
||||
);
|
||||
let edit = if let Some(effort) = effort {
|
||||
ConfigEdit::SetPath {
|
||||
segments,
|
||||
value: effort.to_string().into(),
|
||||
}
|
||||
crate::config_update::replace_config_value(
|
||||
key_path,
|
||||
serde_json::json!(effort.to_string()),
|
||||
)
|
||||
} else {
|
||||
ConfigEdit::ClearPath { segments }
|
||||
crate::config_update::clear_config_value(key_path)
|
||||
};
|
||||
if let Err(err) = ConfigEditsBuilder::for_config(&self.config)
|
||||
.with_edits([edit])
|
||||
.apply()
|
||||
.await
|
||||
if let Err(err) = crate::config_update::write_config_batch(
|
||||
app_server.request_handle(),
|
||||
vec![edit],
|
||||
)
|
||||
.await
|
||||
{
|
||||
tracing::error!(
|
||||
error = %err,
|
||||
|
||||
Reference in New Issue
Block a user