Preserve thread settings for goal-first and forked threads (#34469)

## Why

Goal-first and forked threads could create rollouts without recording their
effective thread settings. Resuming those threads after a restart could then
use current configuration instead of the settings selected when the thread was
created.

## What changed

- Persist a `thread_settings_applied` item when a goal first materializes a
  rollout, including a follow-up snapshot if settings changed concurrently.
- Append each fork's effective settings after its copied history so they take
  precedence over inherited settings during resume.
- Centralize conversion from `ThreadConfigSnapshot` to
  `ThreadSettingsSnapshot`.

## Testing

Added coverage that restarts the app server and verifies goal-first and forked
threads retain their respective `approvals_reviewer` settings.

GitOrigin-RevId: 6cb9aaae73bbe9ca432831cff7e826f95ffd6d01
This commit is contained in:
Dylan Hurd authored and copyberry committed 2026-07-21 05:19:49 +00:00
1 parent 9970cd706f
commit 1836ae0612
7 files changed
+230 -30

No files matched your search

+2 -17
View File
@@ -43,7 +43,6 @@ use codex_protocol::protocol::ThreadMemoryMode;
use codex_protocol::protocol::ThreadRolledBackEvent;
use codex_protocol::protocol::ThreadSettingsAppliedEvent;
use codex_protocol::protocol::ThreadSettingsOverrides;
use codex_protocol::protocol::ThreadSettingsSnapshot;
use codex_protocol::protocol::TurnAbortReason;
use codex_protocol::protocol::WarningEvent;
use codex_protocol::request_permissions::RequestPermissionsResponse;
@@ -165,27 +164,13 @@ async fn thread_settings_update(
}
}
async fn thread_settings_applied_event(sess: &Session) -> EventMsg {
pub(super) async fn thread_settings_applied_event(sess: &Session) -> EventMsg {
let snapshot = {
let state = sess.state.lock().await;
state.session_configuration.thread_config_snapshot()
};
let cwd = snapshot.cwd().clone();
EventMsg::ThreadSettingsApplied(ThreadSettingsAppliedEvent {
thread_settings: ThreadSettingsSnapshot {
model: snapshot.model,
model_provider_id: snapshot.model_provider_id,
service_tier: snapshot.service_tier,
approval_policy: snapshot.approval_policy,
approvals_reviewer: snapshot.approvals_reviewer,
permission_profile: snapshot.permission_profile,
active_permission_profile: snapshot.active_permission_profile,
cwd,
reasoning_effort: snapshot.reasoning_effort,
reasoning_summary: snapshot.reasoning_summary,
personality: snapshot.personality,
collaboration_mode: snapshot.collaboration_mode,
},
thread_settings: snapshot.into_thread_settings_snapshot(),
})
}