Fix first-turn model switching and rollback (#37260)

## Why

A model switch on the first turn has no prior turn settings to compare, and rolling that turn back could leave its model instructions in history.

## What changed

- Track the model that supplied the session's base instructions so first-turn switches inject the target model's instructions, including the selected personality.
- Preserve inherited custom base instructions when starting from an empty fork.
- Remove first-turn model-switch developer content during rollback so retries and cold resumes do not retain or duplicate stale instructions.

## Testing

Add integration coverage for first-turn switches, personality changes, empty-prefix forks, rollback retries, and cold resume.

GitOrigin-RevId: 9df532e9e337521ad3b315b77f8c98e039fb384e
This commit is contained in:
jif authored and copyberry committed 2026-08-06 11:03:31 +00:00
1 parent 82b17bc724
commit a17da5e6e4
7 files changed
+273 -13

No files matched your search

+6 -1
View File
@@ -515,6 +515,7 @@ impl Session {
installation_id: String,
auth_manager: Arc<AuthManager>,
models_manager: SharedModelsManager,
model_info: ModelInfo,
exec_policy: Arc<ExecPolicyManager>,
tx_event: Sender<Event>,
agent_status: watch::Sender<AgentStatus>,
@@ -999,10 +1000,14 @@ impl Session {
session_configuration.thread_name = thread_name.clone();
validate_config_lock_if_configured(&session_configuration).await?;
export_config_lock_if_configured(&session_configuration, thread_id).await?;
let state = SessionState::new_with_auto_compact_window_ids(
let mut state = SessionState::new_with_auto_compact_window_ids(
session_configuration.clone(),
initial_auto_compact_window_ids,
);
state.base_instructions_model = (config.base_instructions.is_none()
&& session_configuration.base_instructions
== model_info.get_model_instructions(config.personality))
.then(|| model_info.slug.clone());
let managed_network_requirements_configured = config
.config_layer_stack
.requirements_toml()