Use thread IDs in TUI resume hints (#18440)

## Summary

Fixes #18313.

Recent TUI resume breadcrumbs could print a thread title instead of the
stable thread UUID. For sessions whose title was auto-derived from the
first prompt, that made the suggested codex resume command look like it
should resume a long prompt rather than the session ID.

This updates the TUI and CLI post-exit resume hints, plus the in-session
summary shown when switching/forking threads, to always use the stable
thread ID for these recovery breadcrumbs. Explicit name-based resume
support remains available elsewhere.
This commit is contained in:
Eric Traut
2026-04-19 22:38:48 -07:00
committed by GitHub
Unverified
parent 80aecc22cd
commit fa8943fe7e
3 changed files with 12 additions and 12 deletions
+4 -4
View File
@@ -476,7 +476,6 @@ fn format_exit_messages(exit_info: AppExitInfo, color_enabled: bool) -> Vec<Stri
let AppExitInfo {
token_usage,
thread_id: conversation_id,
thread_name,
..
} = exit_info;
@@ -489,7 +488,7 @@ fn format_exit_messages(exit_info: AppExitInfo, color_enabled: bool) -> Vec<Stri
}
if let Some(resume_cmd) =
codex_core::util::resume_command(thread_name.as_deref(), conversation_id)
codex_core::util::resume_command(/*thread_name*/ None, conversation_id)
{
let command = if color_enabled {
resume_cmd.cyan().to_string()
@@ -1812,7 +1811,7 @@ mod tests {
}
#[test]
fn format_exit_messages_prefers_thread_name() {
fn format_exit_messages_uses_id_even_when_thread_has_name() {
let exit_info = sample_exit_info(
Some("123e4567-e89b-12d3-a456-426614174000"),
Some("my-thread"),
@@ -1822,7 +1821,8 @@ mod tests {
lines,
vec![
"Token usage: total=2 input=0 output=2".to_string(),
"To continue this session, run codex resume my-thread".to_string(),
"To continue this session, run codex resume 123e4567-e89b-12d3-a456-426614174000"
.to_string(),
]
);
}
+5 -6
View File
@@ -339,11 +339,10 @@ fn session_summary(
rollout_path: Option<&Path>,
) -> Option<SessionSummary> {
let usage_line = (!token_usage.is_zero()).then(|| FinalOutput::from(token_usage).to_string());
let (thread_id, thread_name) = resumable_thread(thread_id, thread_name, rollout_path)
.map(|thread| (Some(thread.thread_id), thread.thread_name))
.unwrap_or((None, None));
let thread_id =
resumable_thread(thread_id, thread_name, rollout_path).map(|thread| thread.thread_id);
let resume_command =
crate::legacy_core::util::resume_command(thread_name.as_deref(), thread_id);
crate::legacy_core::util::resume_command(/*thread_name*/ None, thread_id);
if usage_line.is_none() && resume_command.is_none() {
return None;
@@ -12326,7 +12325,7 @@ guardian_approval = true
}
#[tokio::test]
async fn session_summary_prefers_name_over_id() {
async fn session_summary_uses_id_even_when_thread_has_name() {
let usage = TokenUsage {
input_tokens: 10,
output_tokens: 2,
@@ -12347,7 +12346,7 @@ guardian_approval = true
.expect("summary");
assert_eq!(
summary.resume_command,
Some("codex resume my-session".to_string())
Some("codex resume 123e4567-e89b-12d3-a456-426614174000".to_string())
);
}
}
+3 -2
View File
@@ -13,7 +13,6 @@ fn format_exit_messages(exit_info: AppExitInfo, color_enabled: bool) -> Vec<Stri
let AppExitInfo {
token_usage,
thread_id,
thread_name,
..
} = exit_info;
@@ -22,7 +21,9 @@ fn format_exit_messages(exit_info: AppExitInfo, color_enabled: bool) -> Vec<Stri
lines.push(codex_protocol::protocol::FinalOutput::from(token_usage).to_string());
}
if let Some(resume_cmd) = legacy_core::util::resume_command(thread_name.as_deref(), thread_id) {
if let Some(resume_cmd) =
legacy_core::util::resume_command(/*thread_name*/ None, thread_id)
{
let command = if color_enabled {
format!("\u{1b}[36m{resume_cmd}\u{1b}[39m")
} else {