-
-
Notifications
You must be signed in to change notification settings - Fork 262
Add settings sync mode and collapsible subagent sessions #531
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,10 +1,11 @@ | ||||||||||||||
| use std::path::PathBuf; | ||||||||||||||
|
|
||||||||||||||
| use serde_json::Value; | ||||||||||||||
| use tokio::sync::Mutex; | ||||||||||||||
|
|
||||||||||||||
| use crate::codex::config as codex_config; | ||||||||||||||
| use crate::storage::write_settings; | ||||||||||||||
| use crate::types::AppSettings; | ||||||||||||||
| use crate::storage::{read_settings, write_settings}; | ||||||||||||||
| use crate::types::{AppSettings, SettingsSyncMode}; | ||||||||||||||
|
|
||||||||||||||
| fn normalize_personality(value: &str) -> Option<&'static str> { | ||||||||||||||
| match value.trim() { | ||||||||||||||
|
|
@@ -16,25 +17,27 @@ fn normalize_personality(value: &str) -> Option<&'static str> { | |||||||||||||
|
|
||||||||||||||
| pub(crate) async fn get_app_settings_core(app_settings: &Mutex<AppSettings>) -> AppSettings { | ||||||||||||||
| let mut settings = app_settings.lock().await.clone(); | ||||||||||||||
| if let Ok(Some(collaboration_modes_enabled)) = codex_config::read_collaboration_modes_enabled() | ||||||||||||||
| { | ||||||||||||||
| settings.collaboration_modes_enabled = collaboration_modes_enabled; | ||||||||||||||
| } | ||||||||||||||
| if let Ok(Some(steer_enabled)) = codex_config::read_steer_enabled() { | ||||||||||||||
| settings.steer_enabled = steer_enabled; | ||||||||||||||
| } | ||||||||||||||
| if let Ok(Some(unified_exec_enabled)) = codex_config::read_unified_exec_enabled() { | ||||||||||||||
| settings.unified_exec_enabled = unified_exec_enabled; | ||||||||||||||
| } | ||||||||||||||
| if let Ok(Some(apps_enabled)) = codex_config::read_apps_enabled() { | ||||||||||||||
| settings.experimental_apps_enabled = apps_enabled; | ||||||||||||||
| } | ||||||||||||||
| if let Ok(personality) = codex_config::read_personality() { | ||||||||||||||
| settings.personality = personality | ||||||||||||||
| .as_deref() | ||||||||||||||
| .and_then(normalize_personality) | ||||||||||||||
| .unwrap_or("friendly") | ||||||||||||||
| .to_string(); | ||||||||||||||
| if matches!(settings.sync_mode, SettingsSyncMode::Bidirectional) { | ||||||||||||||
| if let Ok(Some(collaboration_modes_enabled)) = codex_config::read_collaboration_modes_enabled() | ||||||||||||||
| { | ||||||||||||||
| settings.collaboration_modes_enabled = collaboration_modes_enabled; | ||||||||||||||
| } | ||||||||||||||
| if let Ok(Some(steer_enabled)) = codex_config::read_steer_enabled() { | ||||||||||||||
| settings.steer_enabled = steer_enabled; | ||||||||||||||
| } | ||||||||||||||
| if let Ok(Some(unified_exec_enabled)) = codex_config::read_unified_exec_enabled() { | ||||||||||||||
| settings.unified_exec_enabled = unified_exec_enabled; | ||||||||||||||
| } | ||||||||||||||
| if let Ok(Some(apps_enabled)) = codex_config::read_apps_enabled() { | ||||||||||||||
| settings.experimental_apps_enabled = apps_enabled; | ||||||||||||||
| } | ||||||||||||||
| if let Ok(personality) = codex_config::read_personality() { | ||||||||||||||
| settings.personality = personality | ||||||||||||||
| .as_deref() | ||||||||||||||
| .and_then(normalize_personality) | ||||||||||||||
| .unwrap_or("friendly") | ||||||||||||||
| .to_string(); | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
| settings | ||||||||||||||
| } | ||||||||||||||
|
|
@@ -44,15 +47,86 @@ pub(crate) async fn update_app_settings_core( | |||||||||||||
| app_settings: &Mutex<AppSettings>, | ||||||||||||||
| settings_path: &PathBuf, | ||||||||||||||
| ) -> Result<AppSettings, String> { | ||||||||||||||
| let _ = codex_config::write_collaboration_modes_enabled(settings.collaboration_modes_enabled); | ||||||||||||||
| let _ = codex_config::write_steer_enabled(settings.steer_enabled); | ||||||||||||||
| let _ = codex_config::write_unified_exec_enabled(settings.unified_exec_enabled); | ||||||||||||||
| let _ = codex_config::write_apps_enabled(settings.experimental_apps_enabled); | ||||||||||||||
| let _ = codex_config::write_personality(settings.personality.as_str()); | ||||||||||||||
| write_settings(settings_path, &settings)?; | ||||||||||||||
| let previous = app_settings.lock().await.clone(); | ||||||||||||||
| let mut next = settings; | ||||||||||||||
|
|
||||||||||||||
| if matches!(next.sync_mode, SettingsSyncMode::Bidirectional) { | ||||||||||||||
| if let Ok(disk_settings) = read_settings(settings_path) { | ||||||||||||||
|
Comment on lines
+50
to
+54
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This reconciliation path uses Useful? React with 👍 / 👎. |
||||||||||||||
| next = merge_bidirectional_settings(previous.clone(), next, disk_settings)?; | ||||||||||||||
| } | ||||||||||||||
|
Comment on lines
+54
to
+56
|
||||||||||||||
| if let Ok(disk_settings) = read_settings(settings_path) { | |
| next = merge_bidirectional_settings(previous.clone(), next, disk_settings)?; | |
| } | |
| let disk_settings = read_settings(settings_path) | |
| .map_err(|e| format!("Failed to read settings for bidirectional sync: {}", e))?; | |
| next = merge_bidirectional_settings(previous.clone(), next, disk_settings)?; |
Copilot
AI
Feb 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
merge_bidirectional_settings can also overwrite syncMode itself (since it merges all keys when incoming == previous). Because the if matches!(next.sync_mode, Bidirectional) check happens before the merge, reconcile_managed_config_fields will still run even if the merge changes next.sync_mode to AppAuthoritative based on disk. Consider either (a) excluding syncMode from the merge so the mode is always app-driven, or (b) re-checking next.sync_mode after the merge before running bidirectional-only reconciliation logic.
| reconcile_managed_config_fields(&previous, &mut next); | |
| if matches!(next.sync_mode, SettingsSyncMode::Bidirectional) { | |
| reconcile_managed_config_fields(&previous, &mut next); | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PR description says existing behavior is preserved unless sync mode is switched to bidirectional, but
get_app_settings_corenow only pulls values fromcodex_configwhensync_modeis Bidirectional. With the new default (AppAuthoritative), manual edits to the managed Codex config fields will no longer be reflected on reads. If that behavior change is intentional, it may need to be called out explicitly; otherwise consider still reconciling these fields on read in app-authoritative mode (or revising the default).