mirror of
https://github.com/openai/codex.git
synced 2026-05-23 12:34:25 +00:00
Handle thread settings updates in TUI
This commit is contained in:
@@ -163,7 +163,9 @@ impl App {
|
||||
session.model = notification.thread_settings.model.clone();
|
||||
session.model_provider_id = notification.thread_settings.model_provider.clone();
|
||||
session.service_tier = notification.thread_settings.service_tier.clone();
|
||||
session.cwd = notification.thread_settings.cwd.clone();
|
||||
session.set_cwd_retargeting_implicit_runtime_workspace_root(
|
||||
notification.thread_settings.cwd.clone(),
|
||||
);
|
||||
session.approval_policy = notification.thread_settings.approval_policy;
|
||||
session.approvals_reviewer = notification.thread_settings.approvals_reviewer.to_core();
|
||||
session.permission_profile = notification
|
||||
@@ -178,6 +180,7 @@ impl App {
|
||||
.map(codex_protocol::models::ActivePermissionProfile::from);
|
||||
session.reasoning_effort = notification.thread_settings.effort;
|
||||
};
|
||||
let server_notification = ServerNotification::ThreadSettingsUpdated(notification.clone());
|
||||
|
||||
if self.primary_thread_id == Some(thread_id)
|
||||
&& let Some(session) = self.primary_session_configured.as_mut()
|
||||
@@ -189,16 +192,15 @@ impl App {
|
||||
if let Some(session) = store.session.as_mut() {
|
||||
update_session(session);
|
||||
}
|
||||
store.push_notification(server_notification.clone());
|
||||
}
|
||||
|
||||
if self.chat_widget.thread_id() != Some(thread_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.chat_widget.handle_server_notification(
|
||||
ServerNotification::ThreadSettingsUpdated(notification),
|
||||
/*replay_kind*/ None,
|
||||
);
|
||||
self.chat_widget
|
||||
.handle_server_notification(server_notification, /*replay_kind*/ None);
|
||||
}
|
||||
|
||||
async fn handle_server_request_event(
|
||||
|
||||
@@ -234,29 +234,33 @@ async fn thread_settings_updated_notification_reaches_active_thread_ui() -> Resu
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn thread_settings_updated_notification_for_hidden_thread_updates_cache_only() -> Result<()> {
|
||||
async fn hidden_thread_settings_update_buffers_for_replay() -> Result<()> {
|
||||
let (mut app, _app_event_rx, _op_rx) = make_test_app_with_channels().await;
|
||||
let active_thread_id = ThreadId::new();
|
||||
let hidden_thread_id = ThreadId::new();
|
||||
let active_cwd = test_path_buf("/tmp/active").abs();
|
||||
let hidden_cwd = test_path_buf("/tmp/hidden").abs();
|
||||
let hidden_next_cwd = test_path_buf("/tmp/hidden-next").abs();
|
||||
let shared_root = test_path_buf("/tmp/shared").abs();
|
||||
app.enqueue_primary_thread_session(
|
||||
test_thread_session(active_thread_id, active_cwd.to_path_buf()),
|
||||
Vec::new(),
|
||||
)
|
||||
.await?;
|
||||
let mut hidden_session = test_thread_session(hidden_thread_id, hidden_cwd.to_path_buf());
|
||||
hidden_session.runtime_workspace_roots = vec![hidden_cwd.clone(), shared_root.clone()];
|
||||
app.thread_event_channels.insert(
|
||||
hidden_thread_id,
|
||||
ThreadEventChannel::new_with_session(
|
||||
THREAD_EVENT_CHANNEL_CAPACITY,
|
||||
test_thread_session(hidden_thread_id, hidden_cwd.to_path_buf()),
|
||||
hidden_session,
|
||||
Vec::new(),
|
||||
),
|
||||
);
|
||||
|
||||
app.handle_thread_settings_updated_notification(ThreadSettingsUpdatedNotification {
|
||||
thread_id: hidden_thread_id.to_string(),
|
||||
thread_settings: test_thread_settings("gpt-hidden", hidden_cwd),
|
||||
thread_settings: test_thread_settings("gpt-hidden", hidden_next_cwd.clone()),
|
||||
})
|
||||
.await;
|
||||
|
||||
@@ -273,6 +277,21 @@ async fn thread_settings_updated_notification_for_hidden_thread_updates_cache_on
|
||||
.map(|session| session.model.as_str()),
|
||||
Some("gpt-hidden")
|
||||
);
|
||||
let hidden_session = hidden_store.session.as_ref().expect("hidden session");
|
||||
assert_eq!(hidden_session.cwd, hidden_next_cwd);
|
||||
assert_eq!(
|
||||
hidden_session.runtime_workspace_roots,
|
||||
vec![hidden_next_cwd.clone(), shared_root]
|
||||
);
|
||||
assert!(
|
||||
hidden_store.buffer.iter().any(|event| matches!(
|
||||
event,
|
||||
ThreadBufferedEvent::Notification(ServerNotification::ThreadSettingsUpdated(
|
||||
notification
|
||||
)) if notification.thread_settings.model == "gpt-hidden"
|
||||
)),
|
||||
"hidden thread settings update should be buffered for replay"
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ impl ThreadEventStore {
|
||||
ThreadBufferedEvent::Request(_)
|
||||
| ThreadBufferedEvent::Notification(ServerNotification::HookStarted(_))
|
||||
| ThreadBufferedEvent::Notification(ServerNotification::HookCompleted(_))
|
||||
| ThreadBufferedEvent::Notification(ServerNotification::ThreadSettingsUpdated(_))
|
||||
| ThreadBufferedEvent::FeedbackSubmission(_)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -220,7 +220,6 @@ impl ChatWidget {
|
||||
| ServerNotification::AccountRateLimitsUpdated(_)
|
||||
| ServerNotification::ThreadStarted(_)
|
||||
| ServerNotification::ThreadStatusChanged(_)
|
||||
| ServerNotification::ThreadSettingsUpdated(_)
|
||||
| ServerNotification::ThreadArchived(_)
|
||||
| ServerNotification::ThreadUnarchived(_)
|
||||
| ServerNotification::RawResponseItemCompleted(_)
|
||||
@@ -249,8 +248,17 @@ impl ChatWidget {
|
||||
&mut self,
|
||||
thread_settings: codex_app_server_protocol::ThreadSettings,
|
||||
) {
|
||||
let previous_cwd = std::mem::replace(&mut self.config.cwd, thread_settings.cwd.clone());
|
||||
self.current_cwd = Some(thread_settings.cwd.to_path_buf());
|
||||
self.config.cwd = thread_settings.cwd;
|
||||
if crate::session_state::retarget_implicit_workspace_root(
|
||||
&mut self.config.workspace_roots,
|
||||
previous_cwd,
|
||||
thread_settings.cwd.clone(),
|
||||
) {
|
||||
self.config
|
||||
.permissions
|
||||
.set_workspace_roots(self.config.workspace_roots.clone());
|
||||
}
|
||||
self.config.model_reasoning_summary = thread_settings.summary;
|
||||
self.config.personality = thread_settings.personality;
|
||||
self.effective_service_tier = thread_settings.service_tier.clone();
|
||||
|
||||
@@ -4,7 +4,14 @@ use pretty_assertions::assert_eq;
|
||||
#[tokio::test]
|
||||
async fn thread_settings_updated_notification_refreshes_active_ui_state_without_history() {
|
||||
let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.4")).await;
|
||||
let previous_cwd = test_path_buf("/tmp/thread-settings-previous").abs();
|
||||
let cwd = test_path_buf("/tmp/thread-settings").abs();
|
||||
let extra_root = test_path_buf("/tmp/thread-settings-extra-root").abs();
|
||||
chat.config.cwd = previous_cwd.clone();
|
||||
chat.config.workspace_roots = vec![previous_cwd, extra_root.clone()];
|
||||
chat.config
|
||||
.permissions
|
||||
.set_workspace_roots(chat.config.workspace_roots.clone());
|
||||
let permission_profile = PermissionProfile::workspace_write();
|
||||
let collaboration_mode = CollaborationMode {
|
||||
mode: ModeKind::Plan,
|
||||
@@ -63,6 +70,12 @@ async fn thread_settings_updated_notification_refreshes_active_ui_state_without_
|
||||
);
|
||||
assert_eq!(chat.config_ref().personality, Some(Personality::Pragmatic));
|
||||
assert_eq!(chat.current_collaboration_mode(), &collaboration_mode);
|
||||
let expected_workspace_roots = vec![cwd, extra_root];
|
||||
assert_eq!(chat.config_ref().workspace_roots, expected_workspace_roots);
|
||||
assert_eq!(
|
||||
chat.config_ref().permissions.user_visible_workspace_roots(),
|
||||
expected_workspace_roots.as_slice()
|
||||
);
|
||||
assert!(drain_insert_history(&mut rx).is_empty());
|
||||
}
|
||||
|
||||
|
||||
@@ -58,16 +58,25 @@ impl ThreadSessionState {
|
||||
cwd: AbsolutePathBuf,
|
||||
) {
|
||||
let previous_cwd = std::mem::replace(&mut self.cwd, cwd.clone());
|
||||
if !self.runtime_workspace_roots.contains(&previous_cwd) {
|
||||
return;
|
||||
}
|
||||
|
||||
let previous_roots = std::mem::take(&mut self.runtime_workspace_roots);
|
||||
self.runtime_workspace_roots.push(cwd);
|
||||
for root in previous_roots {
|
||||
if root != previous_cwd && !self.runtime_workspace_roots.contains(&root) {
|
||||
self.runtime_workspace_roots.push(root);
|
||||
}
|
||||
}
|
||||
retarget_implicit_workspace_root(&mut self.runtime_workspace_roots, previous_cwd, cwd);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn retarget_implicit_workspace_root(
|
||||
workspace_roots: &mut Vec<AbsolutePathBuf>,
|
||||
previous_cwd: AbsolutePathBuf,
|
||||
cwd: AbsolutePathBuf,
|
||||
) -> bool {
|
||||
if !workspace_roots.contains(&previous_cwd) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let previous_roots = std::mem::take(workspace_roots);
|
||||
workspace_roots.push(cwd);
|
||||
for root in previous_roots {
|
||||
if root != previous_cwd && !workspace_roots.contains(&root) {
|
||||
workspace_roots.push(root);
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user