Fix stale thread-name resume lookups (#16646)

Addresses #15943

Problem: Name-based resume could stop on a newer session_index entry
whose rollout was never persisted, shadowing an older saved thread with
the same name.

Solution: Materialize rollouts before indexing thread names and make
name lookup skip unresolved entries until it finds a persisted rollout.
This commit is contained in:
Eric Traut
2026-04-08 18:51:29 -07:00
committed by GitHub
parent 4dca906e19
commit 36586eafed
7 changed files with 256 additions and 48 deletions
+4 -6
View File
@@ -2090,6 +2090,10 @@ impl ChatWidget {
fn on_thread_name_updated(&mut self, event: codex_protocol::protocol::ThreadNameUpdatedEvent) {
if self.thread_id == Some(event.thread_id) {
if let Some(name) = event.thread_name.as_deref() {
let cell = Self::rename_confirmation_cell(name, self.thread_id);
self.add_boxed_history(Box::new(cell));
}
self.thread_name = event.thread_name;
self.refresh_terminal_title();
self.request_redraw();
@@ -5399,9 +5403,6 @@ impl ChatWidget {
self.add_error_message("Thread name cannot be empty.".to_string());
return;
};
let cell = Self::rename_confirmation_cell(&name, self.thread_id);
self.add_boxed_history(Box::new(cell));
self.request_redraw();
self.app_event_tx.set_thread_name(name);
self.bottom_pane.drain_pending_submission_state();
}
@@ -5479,7 +5480,6 @@ impl ChatWidget {
} else {
"Name thread"
};
let thread_id = self.thread_id;
let view = CustomPromptView::new(
title.to_string(),
"Type a name and press Enter".to_string(),
@@ -5491,8 +5491,6 @@ impl ChatWidget {
)));
return;
};
let cell = Self::rename_confirmation_cell(&name, thread_id);
tx.send(AppEvent::InsertHistoryCell(Box::new(cell)));
tx.set_thread_name(name);
}),
);
@@ -590,6 +590,30 @@ async fn live_app_server_invalid_thread_name_update_is_ignored() {
assert_eq!(chat.thread_name, Some("original name".to_string()));
}
#[tokio::test]
async fn live_app_server_thread_name_update_shows_resume_hint() {
let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await;
let thread_id = ThreadId::new();
chat.thread_id = Some(thread_id);
chat.handle_server_notification(
ServerNotification::ThreadNameUpdated(
codex_app_server_protocol::ThreadNameUpdatedNotification {
thread_id: thread_id.to_string(),
thread_name: Some("review-fix".to_string()),
},
),
/*replay_kind*/ None,
);
assert_eq!(chat.thread_name, Some("review-fix".to_string()));
let cells = drain_insert_history(&mut rx);
assert_eq!(cells.len(), 1);
let rendered = lines_to_single_string(&cells[0]);
assert!(rendered.contains("Thread renamed to review-fix"));
assert!(rendered.contains("codex resume review-fix"));
}
#[tokio::test]
async fn live_app_server_thread_closed_requests_immediate_exit() {
let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await;