mirror of
https://github.com/openai/codex.git
synced 2026-11-05 08:28:29 +00:00
Sync TUI thread settings through app server (#23507)
Builds on #23502. ## Why #23502 adds the app-server `thread/settings/update` API and matching `thread/settings/updated` notification. The TUI already lets users change thread-scoped settings such as model, reasoning effort, service tier, approvals, permissions, personality, and collaboration mode, but those updates need to flow through the app server so embedded and connected clients observe the same thread state. This is a rework (simplification) of PR https://github.com/openai/codex/pull/22510. It has the same functionality, but the underlying `thread/settings/update` api is now simpler in that it no longer returns the effective settings as a response. Now, clients receive the effective settings only through the `thread/settings/updated` notification. ## What Changed This updates the TUI to send `thread/settings/update` whenever those thread-scoped settings change and to treat the RPC response as the authoritative acknowledgement. It also routes `thread/settings/updated` notifications back into cached session state and the visible chat widget so active and inactive threads stay in sync after app-server-originated changes. The implementation is kept to the TUI layer: settings conversion and merge logic live under `codex-rs/tui/src/app/thread_settings.rs`, with dispatch/routing hooks in the existing app and chat widget paths. ## Verification I manually tested using `codex app-server --listen unix://` and then launching two copies of the TUI that use the same local app server. I then resumed the same thread on both and verified that changes like plan mode, fast mode, model, reasoning effort, etc. are reflected "live" in the second client when modified in the first and vice versa.
This commit is contained in:
1 parent
771a4e74ac
commit
edc48e4612
25 files changed
+1086
-16
No files matched your search
@@ -178,7 +178,7 @@ impl ChatWidget {
|
||||
);
|
||||
return;
|
||||
}
|
||||
self.set_collaboration_mask(collaboration_mode);
|
||||
self.set_collaboration_mask_from_user_action(collaboration_mode);
|
||||
let should_queue = self.is_plan_streaming_in_tui();
|
||||
let user_message = UserMessage {
|
||||
text,
|
||||
|
||||
@@ -51,6 +51,9 @@ impl ChatWidget {
|
||||
ServerNotification::ThreadGoalCleared(notification) => {
|
||||
self.on_thread_goal_cleared(notification.thread_id.as_str());
|
||||
}
|
||||
ServerNotification::ThreadSettingsUpdated(notification) => {
|
||||
self.on_thread_settings_updated(notification);
|
||||
}
|
||||
ServerNotification::TurnStarted(notification) => {
|
||||
self.turn_lifecycle.last_turn_id = Some(notification.turn.id);
|
||||
self.last_non_retry_error = None;
|
||||
@@ -247,6 +250,10 @@ impl ChatWidget {
|
||||
notification: TurnCompletedNotification,
|
||||
replay_kind: Option<ReplayKind>,
|
||||
) {
|
||||
// User-message dedupe only suppresses the app-server echo of a prompt
|
||||
// this TUI already rendered locally. Once that turn ends, another
|
||||
// client can submit the same text and it still needs its own user cell.
|
||||
self.last_rendered_user_message_display = None;
|
||||
match notification.turn.status {
|
||||
TurnStatus::Completed => {
|
||||
self.last_non_retry_error = None;
|
||||
|
||||
@@ -73,18 +73,31 @@ impl ChatWidget {
|
||||
}
|
||||
}
|
||||
self.config.approvals_reviewer = session.approvals_reviewer;
|
||||
self.config.personality = session.personality;
|
||||
self.status_line_project_root_name_cache = None;
|
||||
let forked_from_id = session.forked_from_id;
|
||||
let model_for_header = session.model.clone();
|
||||
self.session_header.set_model(&model_for_header);
|
||||
let default_model = session.model.clone();
|
||||
self.current_collaboration_mode = self.current_collaboration_mode.with_updates(
|
||||
Some(model_for_header.clone()),
|
||||
Some(default_model.clone()),
|
||||
Some(session.reasoning_effort),
|
||||
/*developer_instructions*/ None,
|
||||
);
|
||||
if let Some(mask) = self.active_collaboration_mask.as_mut() {
|
||||
mask.model = Some(model_for_header.clone());
|
||||
mask.reasoning_effort = Some(session.reasoning_effort);
|
||||
match session.collaboration_mode.as_deref() {
|
||||
Some(collaboration_mode) => {
|
||||
self.set_effective_collaboration_mode(collaboration_mode.clone());
|
||||
}
|
||||
None => {
|
||||
self.active_collaboration_mask = Self::initial_collaboration_mask(
|
||||
&self.config,
|
||||
self.model_catalog.as_ref(),
|
||||
Some(&default_model),
|
||||
);
|
||||
if let Some(mask) = self.active_collaboration_mask.as_mut() {
|
||||
mask.reasoning_effort = Some(session.reasoning_effort);
|
||||
}
|
||||
self.update_collaboration_mode_indicator();
|
||||
self.refresh_plan_mode_nudge();
|
||||
}
|
||||
}
|
||||
self.refresh_model_display();
|
||||
self.refresh_status_surfaces();
|
||||
@@ -93,6 +106,7 @@ impl ChatWidget {
|
||||
self.sync_plugins_command_enabled();
|
||||
self.sync_goal_command_enabled();
|
||||
self.refresh_plugin_mentions();
|
||||
let model_for_header = self.current_model().to_string();
|
||||
if display == SessionConfiguredDisplay::Normal {
|
||||
let startup_tooltip_override = self.startup_tooltip_override.take();
|
||||
let show_fast_status = self
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//! Runtime settings state and model/collaboration coordination for `ChatWidget`.
|
||||
|
||||
use super::*;
|
||||
use crate::app_event::AppEvent;
|
||||
|
||||
impl ChatWidget {
|
||||
/// Set the approval policy in the widget's config copy.
|
||||
@@ -345,6 +346,24 @@ impl ChatWidget {
|
||||
self.effective_reasoning_effort()
|
||||
}
|
||||
|
||||
pub(crate) fn on_thread_settings_updated(
|
||||
&mut self,
|
||||
notification: ThreadSettingsUpdatedNotification,
|
||||
) {
|
||||
let Ok(thread_id) = ThreadId::from_string(¬ification.thread_id) else {
|
||||
tracing::warn!(
|
||||
thread_id = notification.thread_id,
|
||||
"ignoring app-server ThreadSettingsUpdated with invalid thread_id"
|
||||
);
|
||||
return;
|
||||
};
|
||||
if self.thread_id != Some(thread_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.apply_thread_settings(notification.thread_settings);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn active_collaboration_mode_kind(&self) -> ModeKind {
|
||||
self.active_mode_kind()
|
||||
@@ -430,7 +449,7 @@ impl ChatWidget {
|
||||
.unwrap_or(current_effort)
|
||||
}
|
||||
|
||||
pub(super) fn effective_collaboration_mode(&self) -> CollaborationMode {
|
||||
pub(crate) fn effective_collaboration_mode(&self) -> CollaborationMode {
|
||||
if !self.collaboration_modes_enabled() {
|
||||
return self.current_collaboration_mode.clone();
|
||||
}
|
||||
@@ -462,6 +481,96 @@ impl ChatWidget {
|
||||
self.refresh_status_line();
|
||||
}
|
||||
|
||||
fn apply_thread_settings(&mut self, mut settings: ThreadSettings) {
|
||||
let cwd_changed = self.config.cwd != settings.cwd;
|
||||
self.apply_thread_settings_cwd(settings.cwd.clone());
|
||||
self.config.model_provider_id = settings.model_provider.clone();
|
||||
self.set_service_tier(settings.service_tier.clone());
|
||||
self.set_approval_policy(settings.approval_policy);
|
||||
self.set_approvals_reviewer(settings.approvals_reviewer.to_core());
|
||||
self.config.personality = settings.personality;
|
||||
|
||||
let permission_profile = PermissionProfile::from_legacy_sandbox_policy_for_cwd(
|
||||
&settings.sandbox_policy.to_core(),
|
||||
settings.cwd.as_path(),
|
||||
);
|
||||
let permission_snapshot = PermissionProfileSnapshot::from_session_snapshot(
|
||||
permission_profile,
|
||||
settings.active_permission_profile.take().map(Into::into),
|
||||
);
|
||||
if let Err(err) = self
|
||||
.config
|
||||
.permissions
|
||||
.set_permission_profile_from_session_snapshot(permission_snapshot.clone())
|
||||
{
|
||||
tracing::warn!(%err, "failed to sync permissions from ThreadSettingsUpdated");
|
||||
if let Err(replace_err) = self
|
||||
.config
|
||||
.permissions
|
||||
.replace_permission_profile_from_session_snapshot(permission_snapshot)
|
||||
{
|
||||
tracing::error!(
|
||||
%replace_err,
|
||||
"failed to replace permissions from ThreadSettingsUpdated after constraint fallback"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
settings.collaboration_mode.settings.model = settings.model;
|
||||
settings.collaboration_mode.settings.reasoning_effort = settings.effort;
|
||||
self.set_effective_collaboration_mode(settings.collaboration_mode);
|
||||
self.refresh_status_surfaces();
|
||||
self.sync_service_tier_commands();
|
||||
self.sync_personality_command_enabled();
|
||||
if cwd_changed {
|
||||
self.refresh_skills_for_current_cwd(/*force_reload*/ true);
|
||||
}
|
||||
self.refresh_plugin_mentions();
|
||||
self.request_redraw();
|
||||
}
|
||||
|
||||
fn apply_thread_settings_cwd(&mut self, cwd: AbsolutePathBuf) {
|
||||
let previous_cwd = std::mem::replace(&mut self.config.cwd, cwd.clone());
|
||||
self.current_cwd = Some(cwd.to_path_buf());
|
||||
self.status_line_project_root_name_cache = None;
|
||||
|
||||
if !self.config.workspace_roots.contains(&previous_cwd) {
|
||||
return;
|
||||
}
|
||||
|
||||
let previous_roots = std::mem::take(&mut self.config.workspace_roots);
|
||||
self.config.workspace_roots.push(cwd);
|
||||
for root in previous_roots {
|
||||
if root != previous_cwd && !self.config.workspace_roots.contains(&root) {
|
||||
self.config.workspace_roots.push(root);
|
||||
}
|
||||
}
|
||||
self.config
|
||||
.permissions
|
||||
.set_workspace_roots(self.config.workspace_roots.clone());
|
||||
}
|
||||
|
||||
pub(super) fn set_effective_collaboration_mode(&mut self, mode: CollaborationMode) {
|
||||
let mode_kind = mode.mode;
|
||||
let settings = mode.settings;
|
||||
if mode_kind == ModeKind::Default {
|
||||
self.current_collaboration_mode = CollaborationMode {
|
||||
mode: ModeKind::Default,
|
||||
settings: settings.clone(),
|
||||
};
|
||||
}
|
||||
self.active_collaboration_mask = Some(CollaborationModeMask {
|
||||
name: mode_kind.display_name().to_string(),
|
||||
mode: Some(mode_kind),
|
||||
model: Some(settings.model.clone()),
|
||||
reasoning_effort: Some(settings.reasoning_effort),
|
||||
developer_instructions: Some(settings.developer_instructions),
|
||||
});
|
||||
self.update_collaboration_mode_indicator();
|
||||
self.refresh_plan_mode_nudge();
|
||||
self.refresh_model_dependent_surfaces();
|
||||
}
|
||||
|
||||
pub(super) fn model_display_name(&self) -> &str {
|
||||
let model = self.current_model();
|
||||
if model.is_empty() {
|
||||
@@ -555,10 +664,15 @@ impl ChatWidget {
|
||||
self.model_catalog.as_ref(),
|
||||
self.active_collaboration_mask.as_ref(),
|
||||
) {
|
||||
self.set_collaboration_mask(next_mask);
|
||||
self.set_collaboration_mask_from_user_action(next_mask);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_collaboration_mask_from_user_action(&mut self, mask: CollaborationModeMask) {
|
||||
self.set_collaboration_mask(mask);
|
||||
self.submit_collaboration_mode_settings_update();
|
||||
}
|
||||
|
||||
/// Update the active collaboration mask.
|
||||
///
|
||||
/// When collaboration modes are enabled and a preset is selected,
|
||||
@@ -609,4 +723,26 @@ impl ChatWidget {
|
||||
}
|
||||
self.request_redraw();
|
||||
}
|
||||
|
||||
fn submit_collaboration_mode_settings_update(&self) {
|
||||
let Some(thread_id) = self.thread_id else {
|
||||
return;
|
||||
};
|
||||
self.app_event_tx.send(AppEvent::SubmitThreadOp {
|
||||
thread_id,
|
||||
op: AppCommand::override_turn_context(
|
||||
/*cwd*/ None,
|
||||
/*approval_policy*/ None,
|
||||
/*approvals_reviewer*/ None,
|
||||
/*active_permission_profile*/ None,
|
||||
/*windows_sandbox_level*/ None,
|
||||
/*model*/ None,
|
||||
/*effort*/ None,
|
||||
/*summary*/ None,
|
||||
/*service_tier*/ None,
|
||||
Some(self.effective_collaboration_mode()),
|
||||
/*personality*/ None,
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -88,7 +88,7 @@ impl ChatWidget {
|
||||
return false;
|
||||
}
|
||||
if let Some(mask) = collaboration_modes::plan_mask(self.model_catalog.as_ref()) {
|
||||
self.set_collaboration_mask(mask);
|
||||
self.set_collaboration_mask_from_user_action(mask);
|
||||
true
|
||||
} else {
|
||||
self.add_info_message(
|
||||
|
||||
@@ -1,6 +1,65 @@
|
||||
use super::*;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
fn thread_settings_for_test(
|
||||
model: &str,
|
||||
thread_id: ThreadId,
|
||||
) -> codex_app_server_protocol::ThreadSettingsUpdatedNotification {
|
||||
codex_app_server_protocol::ThreadSettingsUpdatedNotification {
|
||||
thread_id: thread_id.to_string(),
|
||||
thread_settings: codex_app_server_protocol::ThreadSettings {
|
||||
cwd: test_path_buf("/tmp/thread-settings").abs(),
|
||||
approval_policy: AskForApproval::OnRequest,
|
||||
approvals_reviewer: codex_app_server_protocol::ApprovalsReviewer::AutoReview,
|
||||
sandbox_policy: codex_app_server_protocol::SandboxPolicy::ReadOnly {
|
||||
network_access: false,
|
||||
},
|
||||
active_permission_profile: Some(
|
||||
codex_app_server_protocol::ActivePermissionProfile::read_only(),
|
||||
),
|
||||
model: model.to_string(),
|
||||
model_provider: "openai".to_string(),
|
||||
service_tier: Some(ServiceTier::Fast.request_value().to_string()),
|
||||
effort: Some(ReasoningEffortConfig::High),
|
||||
summary: None,
|
||||
collaboration_mode: CollaborationMode {
|
||||
mode: ModeKind::Plan,
|
||||
settings: codex_protocol::config_types::Settings {
|
||||
model: model.to_string(),
|
||||
reasoning_effort: Some(ReasoningEffortConfig::High),
|
||||
developer_instructions: None,
|
||||
},
|
||||
},
|
||||
personality: Some(Personality::Pragmatic),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn configured_thread_session(thread_id: ThreadId) -> crate::session_state::ThreadSessionState {
|
||||
crate::session_state::ThreadSessionState {
|
||||
thread_id,
|
||||
forked_from_id: None,
|
||||
fork_parent_title: None,
|
||||
thread_name: None,
|
||||
model: "gpt-5.3-codex".to_string(),
|
||||
model_provider_id: "openai".to_string(),
|
||||
service_tier: None,
|
||||
approval_policy: AskForApproval::Never,
|
||||
approvals_reviewer: ApprovalsReviewer::User,
|
||||
permission_profile: PermissionProfile::read_only(),
|
||||
active_permission_profile: None,
|
||||
cwd: test_path_buf("/tmp/thread-settings").abs(),
|
||||
runtime_workspace_roots: vec![test_path_buf("/tmp/thread-settings").abs()],
|
||||
instruction_source_paths: Vec::new(),
|
||||
reasoning_effort: None,
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
message_history: None,
|
||||
network_proxy: None,
|
||||
rollout_path: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn invalid_url_elicitation_is_declined() {
|
||||
let (mut chat, _app_event_tx, mut rx, _op_rx) = make_chatwidget_manual_with_sender().await;
|
||||
@@ -38,6 +97,98 @@ async fn invalid_url_elicitation_is_declined() {
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn thread_settings_updated_updates_visible_state_without_transcript() {
|
||||
let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.3-codex")).await;
|
||||
set_fast_mode_test_catalog(&mut chat);
|
||||
let thread_id = ThreadId::new();
|
||||
chat.handle_thread_session(configured_thread_session(thread_id));
|
||||
let _ = drain_insert_history(&mut rx);
|
||||
|
||||
chat.handle_server_notification(
|
||||
ServerNotification::ThreadSettingsUpdated(thread_settings_for_test("gpt-5.4", thread_id)),
|
||||
/*replay_kind*/ None,
|
||||
);
|
||||
|
||||
assert_eq!(chat.current_model(), "gpt-5.4");
|
||||
assert_eq!(
|
||||
chat.current_reasoning_effort(),
|
||||
Some(ReasoningEffortConfig::High)
|
||||
);
|
||||
assert_eq!(
|
||||
chat.current_service_tier(),
|
||||
Some(ServiceTier::Fast.request_value())
|
||||
);
|
||||
assert_eq!(
|
||||
chat.config_ref().permissions.approval_policy.value(),
|
||||
AskForApproval::OnRequest.to_core()
|
||||
);
|
||||
assert_eq!(
|
||||
chat.config_ref().approvals_reviewer,
|
||||
ApprovalsReviewer::AutoReview
|
||||
);
|
||||
assert_eq!(
|
||||
chat.config_ref()
|
||||
.permissions
|
||||
.active_permission_profile()
|
||||
.expect("active profile")
|
||||
.id,
|
||||
codex_protocol::models::BUILT_IN_PERMISSION_PROFILE_READ_ONLY
|
||||
);
|
||||
assert_eq!(chat.config_ref().personality, Some(Personality::Pragmatic));
|
||||
assert_eq!(chat.active_collaboration_mode_kind(), ModeKind::Plan);
|
||||
assert!(
|
||||
drain_insert_history(&mut rx).is_empty(),
|
||||
"ThreadSettingsUpdated should not render transcript history"
|
||||
);
|
||||
|
||||
chat.handle_server_notification(
|
||||
ServerNotification::ThreadSettingsUpdated(thread_settings_for_test(
|
||||
"gpt-5.2",
|
||||
ThreadId::new(),
|
||||
)),
|
||||
/*replay_kind*/ None,
|
||||
);
|
||||
|
||||
assert_eq!(chat.current_model(), "gpt-5.4");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn thread_settings_updated_preserves_default_settings_for_plan_mode() {
|
||||
let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.3-codex")).await;
|
||||
let thread_id = ThreadId::new();
|
||||
let mut session = configured_thread_session(thread_id);
|
||||
session.model = "gpt-default".to_string();
|
||||
session.reasoning_effort = Some(ReasoningEffortConfig::Low);
|
||||
chat.handle_thread_session(session);
|
||||
let _ = drain_insert_history(&mut rx);
|
||||
let default_mode = chat.current_collaboration_mode().clone();
|
||||
|
||||
chat.handle_server_notification(
|
||||
ServerNotification::ThreadSettingsUpdated(thread_settings_for_test("gpt-plan", thread_id)),
|
||||
/*replay_kind*/ None,
|
||||
);
|
||||
|
||||
assert_eq!(chat.active_collaboration_mode_kind(), ModeKind::Plan);
|
||||
assert_eq!(chat.current_model(), "gpt-plan");
|
||||
assert_eq!(
|
||||
chat.current_reasoning_effort(),
|
||||
Some(ReasoningEffortConfig::High)
|
||||
);
|
||||
assert_eq!(chat.current_collaboration_mode(), &default_mode);
|
||||
|
||||
let default_mask = collaboration_modes::default_mask(chat.model_catalog.as_ref())
|
||||
.expect("expected default collaboration mode");
|
||||
chat.set_collaboration_mask(default_mask);
|
||||
|
||||
assert_eq!(chat.active_collaboration_mode_kind(), ModeKind::Default);
|
||||
assert_eq!(chat.current_model(), "gpt-default");
|
||||
assert_eq!(
|
||||
chat.current_reasoning_effort(),
|
||||
Some(ReasoningEffortConfig::Low)
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn collab_spawn_end_shows_requested_model_and_effort() {
|
||||
let (mut chat, mut rx, _ops) = make_chatwidget_manual(/*model_override*/ None).await;
|
||||
|
||||
@@ -30,6 +30,8 @@ async fn submission_preserves_text_elements_and_local_images() {
|
||||
runtime_workspace_roots: Vec::new(),
|
||||
instruction_source_paths: Vec::new(),
|
||||
reasoning_effort: Some(ReasoningEffortConfig::default()),
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
message_history: None,
|
||||
network_proxy: None,
|
||||
rollout_path: Some(rollout_file.path().to_path_buf()),
|
||||
@@ -135,6 +137,8 @@ async fn submission_includes_configured_active_permission_profile() {
|
||||
runtime_workspace_roots: Vec::new(),
|
||||
instruction_source_paths: Vec::new(),
|
||||
reasoning_effort: Some(ReasoningEffortConfig::default()),
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
message_history: None,
|
||||
network_proxy: None,
|
||||
rollout_path: Some(rollout_file.path().to_path_buf()),
|
||||
@@ -188,6 +192,8 @@ async fn submission_omits_active_permission_profile_for_legacy_snapshot() {
|
||||
runtime_workspace_roots: Vec::new(),
|
||||
instruction_source_paths: Vec::new(),
|
||||
reasoning_effort: Some(ReasoningEffortConfig::default()),
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
message_history: None,
|
||||
network_proxy: None,
|
||||
rollout_path: Some(rollout_file.path().to_path_buf()),
|
||||
@@ -231,6 +237,8 @@ async fn submission_with_remote_and_local_images_keeps_local_placeholder_numberi
|
||||
runtime_workspace_roots: Vec::new(),
|
||||
instruction_source_paths: Vec::new(),
|
||||
reasoning_effort: Some(ReasoningEffortConfig::default()),
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
message_history: None,
|
||||
network_proxy: None,
|
||||
rollout_path: Some(rollout_file.path().to_path_buf()),
|
||||
@@ -327,6 +335,8 @@ async fn enter_with_only_remote_images_submits_user_turn() {
|
||||
runtime_workspace_roots: Vec::new(),
|
||||
instruction_source_paths: Vec::new(),
|
||||
reasoning_effort: Some(ReasoningEffortConfig::default()),
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
message_history: None,
|
||||
network_proxy: None,
|
||||
rollout_path: Some(rollout_file.path().to_path_buf()),
|
||||
@@ -392,6 +402,8 @@ async fn shift_enter_with_only_remote_images_does_not_submit_user_turn() {
|
||||
runtime_workspace_roots: Vec::new(),
|
||||
instruction_source_paths: Vec::new(),
|
||||
reasoning_effort: Some(ReasoningEffortConfig::default()),
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
message_history: None,
|
||||
network_proxy: None,
|
||||
rollout_path: Some(rollout_file.path().to_path_buf()),
|
||||
@@ -431,6 +443,8 @@ async fn enter_with_only_remote_images_does_not_submit_when_modal_is_active() {
|
||||
runtime_workspace_roots: Vec::new(),
|
||||
instruction_source_paths: Vec::new(),
|
||||
reasoning_effort: Some(ReasoningEffortConfig::default()),
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
message_history: None,
|
||||
network_proxy: None,
|
||||
rollout_path: Some(rollout_file.path().to_path_buf()),
|
||||
@@ -470,6 +484,8 @@ async fn enter_with_only_remote_images_does_not_submit_when_input_disabled() {
|
||||
runtime_workspace_roots: Vec::new(),
|
||||
instruction_source_paths: Vec::new(),
|
||||
reasoning_effort: Some(ReasoningEffortConfig::default()),
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
message_history: None,
|
||||
network_proxy: None,
|
||||
rollout_path: Some(rollout_file.path().to_path_buf()),
|
||||
@@ -512,6 +528,8 @@ async fn submission_prefers_selected_duplicate_skill_path() {
|
||||
runtime_workspace_roots: Vec::new(),
|
||||
instruction_source_paths: Vec::new(),
|
||||
reasoning_effort: Some(ReasoningEffortConfig::default()),
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
message_history: None,
|
||||
network_proxy: None,
|
||||
rollout_path: Some(rollout_file.path().to_path_buf()),
|
||||
|
||||
@@ -976,6 +976,8 @@ async fn bang_shell_enter_while_task_running_submits_run_user_shell_command() {
|
||||
runtime_workspace_roots: Vec::new(),
|
||||
instruction_source_paths: Vec::new(),
|
||||
reasoning_effort: Some(ReasoningEffortConfig::default()),
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
message_history: None,
|
||||
network_proxy: None,
|
||||
rollout_path: Some(rollout_file.path().to_path_buf()),
|
||||
|
||||
@@ -31,6 +31,8 @@ async fn resumed_initial_messages_render_history() {
|
||||
runtime_workspace_roots: Vec::new(),
|
||||
instruction_source_paths: Vec::new(),
|
||||
reasoning_effort: Some(ReasoningEffortConfig::default()),
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
message_history: None,
|
||||
network_proxy: None,
|
||||
rollout_path: Some(rollout_file.path().to_path_buf()),
|
||||
@@ -102,6 +104,8 @@ async fn replayed_user_message_preserves_text_elements_and_local_images() {
|
||||
runtime_workspace_roots: Vec::new(),
|
||||
instruction_source_paths: Vec::new(),
|
||||
reasoning_effort: Some(ReasoningEffortConfig::default()),
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
message_history: None,
|
||||
network_proxy: None,
|
||||
rollout_path: Some(rollout_file.path().to_path_buf()),
|
||||
@@ -172,6 +176,8 @@ async fn replayed_user_message_preserves_remote_image_urls() {
|
||||
runtime_workspace_roots: Vec::new(),
|
||||
instruction_source_paths: Vec::new(),
|
||||
reasoning_effort: Some(ReasoningEffortConfig::default()),
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
message_history: None,
|
||||
network_proxy: None,
|
||||
rollout_path: Some(rollout_file.path().to_path_buf()),
|
||||
@@ -272,6 +278,8 @@ async fn session_configured_syncs_widget_config_permissions_and_cwd() {
|
||||
runtime_workspace_roots: vec![expected_cwd.clone()],
|
||||
instruction_source_paths: Vec::new(),
|
||||
reasoning_effort: Some(ReasoningEffortConfig::default()),
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
message_history: None,
|
||||
network_proxy: None,
|
||||
rollout_path: None,
|
||||
@@ -343,6 +351,8 @@ async fn session_configured_preserves_profile_workspace_roots() {
|
||||
runtime_workspace_roots: session_runtime_workspace_roots.clone(),
|
||||
instruction_source_paths: Vec::new(),
|
||||
reasoning_effort: Some(ReasoningEffortConfig::default()),
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
message_history: None,
|
||||
network_proxy: None,
|
||||
rollout_path: None,
|
||||
@@ -388,6 +398,8 @@ async fn session_configured_external_sandbox_keeps_external_runtime_policy() {
|
||||
runtime_workspace_roots: Vec::new(),
|
||||
instruction_source_paths: Vec::new(),
|
||||
reasoning_effort: Some(ReasoningEffortConfig::default()),
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
message_history: None,
|
||||
network_proxy: None,
|
||||
rollout_path: None,
|
||||
@@ -427,6 +439,8 @@ async fn replayed_user_message_with_only_remote_images_renders_history_cell() {
|
||||
runtime_workspace_roots: Vec::new(),
|
||||
instruction_source_paths: Vec::new(),
|
||||
reasoning_effort: Some(ReasoningEffortConfig::default()),
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
message_history: None,
|
||||
network_proxy: None,
|
||||
rollout_path: Some(rollout_file.path().to_path_buf()),
|
||||
@@ -483,6 +497,8 @@ async fn replayed_user_message_with_only_local_images_renders_history_cell() {
|
||||
runtime_workspace_roots: Vec::new(),
|
||||
instruction_source_paths: Vec::new(),
|
||||
reasoning_effort: Some(ReasoningEffortConfig::default()),
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
message_history: None,
|
||||
network_proxy: None,
|
||||
rollout_path: Some(rollout_file.path().to_path_buf()),
|
||||
@@ -755,6 +771,8 @@ async fn replayed_reasoning_item_hides_raw_reasoning_when_disabled() {
|
||||
runtime_workspace_roots: Vec::new(),
|
||||
instruction_source_paths: Vec::new(),
|
||||
reasoning_effort: None,
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
message_history: None,
|
||||
network_proxy: None,
|
||||
rollout_path: None,
|
||||
@@ -801,6 +819,8 @@ async fn replayed_reasoning_item_shows_raw_reasoning_when_enabled() {
|
||||
runtime_workspace_roots: Vec::new(),
|
||||
instruction_source_paths: Vec::new(),
|
||||
reasoning_effort: None,
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
message_history: None,
|
||||
network_proxy: None,
|
||||
rollout_path: None,
|
||||
|
||||
@@ -584,6 +584,8 @@ async fn permissions_selection_marks_auto_review_current_after_session_configure
|
||||
runtime_workspace_roots: Vec::new(),
|
||||
instruction_source_paths: Vec::new(),
|
||||
reasoning_effort: None,
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
message_history: None,
|
||||
network_proxy: None,
|
||||
rollout_path: Some(PathBuf::new()),
|
||||
@@ -632,6 +634,8 @@ async fn permissions_selection_marks_auto_review_current_with_custom_workspace_w
|
||||
runtime_workspace_roots: Vec::new(),
|
||||
instruction_source_paths: Vec::new(),
|
||||
reasoning_effort: None,
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
message_history: None,
|
||||
network_proxy: None,
|
||||
rollout_path: Some(PathBuf::new()),
|
||||
|
||||
@@ -1220,6 +1220,8 @@ async fn submit_user_message_emits_structured_plugin_mentions_from_bindings() {
|
||||
runtime_workspace_roots: Vec::new(),
|
||||
instruction_source_paths: Vec::new(),
|
||||
reasoning_effort: Some(ReasoningEffortConfig::default()),
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
message_history: None,
|
||||
network_proxy: None,
|
||||
rollout_path: Some(rollout_file.path().to_path_buf()),
|
||||
@@ -1407,6 +1409,8 @@ async fn plan_slash_command_with_args_submits_prompt_in_plan_mode() {
|
||||
runtime_workspace_roots: Vec::new(),
|
||||
instruction_source_paths: Vec::new(),
|
||||
reasoning_effort: Some(ReasoningEffortConfig::default()),
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
message_history: None,
|
||||
network_proxy: None,
|
||||
rollout_path: None,
|
||||
|
||||
@@ -2493,6 +2493,8 @@ async fn session_configured_clears_goal_status_footer() {
|
||||
runtime_workspace_roots: Vec::new(),
|
||||
instruction_source_paths: Vec::new(),
|
||||
reasoning_effort: Some(ReasoningEffortConfig::default()),
|
||||
collaboration_mode: None,
|
||||
personality: None,
|
||||
message_history: None,
|
||||
network_proxy: None,
|
||||
rollout_path: Some(rollout_file.path().to_path_buf()),
|
||||
|
||||
Reference in new issue
Block a user