TUI: Add session resume picker (--resume) and quick resume (--continue) (#3135)

Adds a TUI resume flow with an interactive picker and quick resume.

- CLI: 
  - --resume / -r: open picker to resume a prior session
  - --continue   / -l: resume the most recent session (no picker)
- Behavior on resume: initial history is replayed, welcome banner
hidden, and the first redraw is suppressed to avoid flicker.
- Implementation:
- New tui/src/resume_picker.rs (paginated listing via
RolloutRecorder::list_conversations)
  - App::run accepts ResumeSelection; resumes from disk when requested
- ChatWidget refactor with ChatWidgetInit and new_from_existing; replays
initial messages
- Tests: cover picker sorting/preview extraction and resumed-history
rendering.
- Docs: getting-started updated with flags and picker usage.



https://github.com/user-attachments/assets/1bb6469b-e5d1-42f6-bec6-b1ae6debda3b
This commit is contained in:
Ahmed Ibrahim
2025-09-03 23:20:40 -07:00
committed by GitHub
parent 0f4ae1b5b0
commit 234c0a0469
11 changed files with 804 additions and 55 deletions

View File

@@ -7,6 +7,7 @@ use app::App;
use codex_core::AuthManager;
use codex_core::BUILT_IN_OSS_MODEL_PROVIDER_ID;
use codex_core::CodexAuth;
use codex_core::RolloutRecorder;
use codex_core::config::Config;
use codex_core::config::ConfigOverrides;
use codex_core::config::ConfigToml;
@@ -47,6 +48,7 @@ mod markdown_stream;
pub mod onboarding;
mod pager_overlay;
mod render;
mod resume_picker;
mod session_log;
mod shimmer;
mod slash_command;
@@ -299,7 +301,13 @@ async fn run_ratatui_app(
// Initialize high-fidelity session event logging if enabled.
session_log::maybe_init(&config);
let Cli { prompt, images, .. } = cli;
let Cli {
prompt,
images,
resume,
r#continue,
..
} = cli;
let auth_manager = AuthManager::shared(
config.codex_home.clone(),
@@ -327,7 +335,37 @@ async fn run_ratatui_app(
}
}
let app_result = App::run(&mut tui, auth_manager, config, prompt, images).await;
let resume_selection = if r#continue {
match RolloutRecorder::list_conversations(&config.codex_home, 1, None).await {
Ok(page) => page
.items
.first()
.map(|it| resume_picker::ResumeSelection::Resume(it.path.clone()))
.unwrap_or(resume_picker::ResumeSelection::StartFresh),
Err(_) => resume_picker::ResumeSelection::StartFresh,
}
} else if resume {
match resume_picker::run_resume_picker(&mut tui, &config.codex_home).await? {
resume_picker::ResumeSelection::Exit => {
restore();
session_log::log_session_end();
return Ok(codex_core::protocol::TokenUsage::default());
}
other => other,
}
} else {
resume_picker::ResumeSelection::StartFresh
};
let app_result = App::run(
&mut tui,
auth_manager,
config,
prompt,
images,
resume_selection,
)
.await;
restore();
// Mark the end of the recorded session.