diff --git a/crates/tui/src/commands/session.rs b/crates/tui/src/commands/session.rs index 6f3a4257d..e4503d910 100644 --- a/crates/tui/src/commands/session.rs +++ b/crates/tui/src/commands/session.rs @@ -94,8 +94,7 @@ pub fn load(app: &mut App, path: Option<&str>) -> CommandResult { app.extend_history(cells_to_add); app.mark_history_updated(); app.viewport.transcript_selection.clear(); - app.model.clone_from(&session.metadata.model); - app.update_model_compaction_budget(); + app.restore_model_selection(session.metadata.model.clone()); app.workspace.clone_from(&session.metadata.workspace); app.session.total_tokens = u32::try_from(session.metadata.total_tokens).unwrap_or(u32::MAX); app.session.total_conversation_tokens = app.session.total_tokens; @@ -448,6 +447,44 @@ mod tests { assert!(matches!(result.action, Some(AppAction::SyncSession { .. }))); } + #[test] + fn load_auto_model_session_restores_auto_mode() { + let tmpdir = TempDir::new().unwrap(); + let mut saved_app = create_test_app_with_tmpdir(&tmpdir); + saved_app.model = "auto".to_string(); + saved_app.auto_model = true; + saved_app.reasoning_effort = crate::tui::app::ReasoningEffort::Auto; + saved_app.api_messages.push(crate::models::Message { + role: "user".to_string(), + content: vec![crate::models::ContentBlock::Text { + text: "Hello".to_string(), + cache_control: None, + }], + }); + let save_path = tmpdir.path().join("auto_model.json"); + save(&mut saved_app, Some(save_path.to_str().unwrap())); + + let mut app = create_test_app_with_tmpdir(&tmpdir); + app.auto_model = false; + app.model = crate::config::DEFAULT_TEXT_MODEL.to_string(); + + let result = load(&mut app, Some(save_path.to_str().unwrap())); + + assert!(!result.is_error); + assert_eq!(app.model, "auto"); + assert!(app.auto_model); + assert_eq!(app.last_effective_model, None); + assert_eq!(app.reasoning_effort, crate::tui::app::ReasoningEffort::Auto); + assert_eq!( + app.effective_model_for_budget(), + crate::config::DEFAULT_TEXT_MODEL + ); + match result.action { + Some(AppAction::SyncSession { model, .. }) => assert_eq!(model, "auto"), + other => panic!("expected SyncSession action, got {other:?}"), + } + } + #[test] fn load_restores_artifact_registry() { let tmpdir = TempDir::new().unwrap(); diff --git a/crates/tui/src/tui/app.rs b/crates/tui/src/tui/app.rs index 7d0346533..15d2d2aab 100644 --- a/crates/tui/src/tui/app.rs +++ b/crates/tui/src/tui/app.rs @@ -3991,6 +3991,18 @@ impl App { compaction_threshold_for_model_and_effort(&model, self.reasoning_effort.api_value()); } + pub fn restore_model_selection(&mut self, model: String) { + let auto_model = model.trim().eq_ignore_ascii_case("auto"); + self.model = model; + self.auto_model = auto_model; + self.last_effective_model = None; + self.last_effective_reasoning_effort = None; + if auto_model { + self.reasoning_effort = ReasoningEffort::Auto; + } + self.update_model_compaction_budget(); + } + pub fn effective_model_for_budget(&self) -> &str { if self.auto_model { return self diff --git a/crates/tui/src/tui/ui.rs b/crates/tui/src/tui/ui.rs index 520bda732..f3ab802cb 100644 --- a/crates/tui/src/tui/ui.rs +++ b/crates/tui/src/tui/ui.rs @@ -6202,8 +6202,7 @@ fn apply_loaded_session(app: &mut App, config: &Config, session: &SavedSession) app.sync_context_references_from_session(&session.context_references, &message_to_cell); app.mark_history_updated(); app.viewport.transcript_selection.clear(); - app.model.clone_from(&session.metadata.model); - app.update_model_compaction_budget(); + app.restore_model_selection(session.metadata.model.clone()); apply_workspace_runtime_state(app, config, session.metadata.workspace.clone()); app.session.total_tokens = u32::try_from(session.metadata.total_tokens).unwrap_or(u32::MAX); app.session.total_conversation_tokens = app.session.total_tokens; diff --git a/crates/tui/src/tui/ui/tests.rs b/crates/tui/src/tui/ui/tests.rs index edbabbae6..3c87ce823 100644 --- a/crates/tui/src/tui/ui/tests.rs +++ b/crates/tui/src/tui/ui/tests.rs @@ -1367,6 +1367,27 @@ fn apply_loaded_session_resets_unpersisted_telemetry() { assert!(app.session.turn_cache_history.is_empty()); } +#[test] +fn apply_loaded_session_restores_auto_model_mode() { + let mut app = create_test_app(); + app.auto_model = false; + app.model = crate::config::DEFAULT_TEXT_MODEL.to_string(); + let mut session = saved_session_with_messages(vec![text_message("assistant", "ready")]); + session.metadata.model = "auto".to_string(); + + let recovered = apply_loaded_session(&mut app, &Config::default(), &session); + + assert!(!recovered); + assert_eq!(app.model, "auto"); + assert!(app.auto_model); + assert_eq!(app.last_effective_model, None); + assert_eq!(app.reasoning_effort, crate::tui::app::ReasoningEffort::Auto); + assert_eq!( + app.effective_model_for_budget(), + crate::config::DEFAULT_TEXT_MODEL + ); +} + #[tokio::test] async fn apply_loaded_session_resets_workspace_runtime_state() { let mut app = create_test_app();