Conversation naming (#8991)

Session renaming:
- `/rename my_session`
- `/rename` without arg and passing an argument in `customViewPrompt`
- AppExitInfo shows resume hint using the session name if set instead of
uuid, defaults to uuid if not set
- Names are stored in `CODEX_HOME/sessions.jsonl`

Session resuming:
- codex resume <name> lookup for `CODEX_HOME/sessions.jsonl` first entry
matching the name and resumes the session

---------

Co-authored-by: jif-oai <jif@openai.com>
This commit is contained in:
pap-openai
2026-01-30 10:40:09 +00:00
committed by GitHub
co-authored by jif-oai
parent 25ad414680
commit 1ef5455eb6
33 changed files with 908 additions and 30 deletions
+2 -2
View File
@@ -114,7 +114,7 @@ pub enum Command {
struct ResumeArgsRaw {
// Note: This is the direct clap shape. We reinterpret the positional when --last is set
// so "codex resume --last <prompt>" treats the positional as a prompt, not a session id.
/// Conversation/session id (UUID). When provided, resumes this session.
/// Conversation/session id (UUID) or thread name. UUIDs take precedence if it parses.
/// If omitted, use --last to pick the most recent recorded session.
#[arg(value_name = "SESSION_ID")]
session_id: Option<String>,
@@ -144,7 +144,7 @@ struct ResumeArgsRaw {
#[derive(Debug)]
pub struct ResumeArgs {
/// Conversation/session id (UUID). When provided, resumes this session.
/// Conversation/session id (UUID) or thread name. UUIDs take precedence if it parses.
/// If omitted, use --last to pick the most recent recorded session.
pub session_id: Option<String>,
@@ -750,7 +750,8 @@ impl EventProcessor for EventProcessorWithHumanOutput {
);
}
EventMsg::ShutdownComplete => return CodexStatus::Shutdown,
EventMsg::ExecApprovalRequest(_)
EventMsg::ThreadNameUpdated(_)
| EventMsg::ExecApprovalRequest(_)
| EventMsg::ApplyPatchApprovalRequest(_)
| EventMsg::TerminalInteraction(_)
| EventMsg::ExecCommandOutputDelta(_)
@@ -117,6 +117,7 @@ impl EventProcessorWithJsonOutput {
pub fn collect_thread_events(&mut self, event: &protocol::Event) -> Vec<ThreadEvent> {
match &event.msg {
protocol::EventMsg::SessionConfigured(ev) => self.handle_session_configured(ev),
protocol::EventMsg::ThreadNameUpdated(_) => Vec::new(),
protocol::EventMsg::AgentMessage(ev) => self.handle_agent_message(ev),
protocol::EventMsg::AgentReasoning(ev) => self.handle_reasoning_event(ev),
protocol::EventMsg::ExecCommandBegin(ev) => self.handle_exec_command_begin(ev),
+9 -2
View File
@@ -59,12 +59,14 @@ use tracing::info;
use tracing::warn;
use tracing_subscriber::EnvFilter;
use tracing_subscriber::prelude::*;
use uuid::Uuid;
use crate::cli::Command as ExecCommand;
use crate::event_processor::CodexStatus;
use crate::event_processor::EventProcessor;
use codex_core::default_client::set_default_originator;
use codex_core::find_thread_path_by_id_str;
use codex_core::find_thread_path_by_name_str;
enum InitialOperation {
UserTurn {
@@ -619,8 +621,13 @@ async fn resolve_resume_path(
}
}
} else if let Some(id_str) = args.session_id.as_deref() {
let path = find_thread_path_by_id_str(&config.codex_home, id_str).await?;
Ok(path)
if Uuid::parse_str(id_str).is_ok() {
let path = find_thread_path_by_id_str(&config.codex_home, id_str).await?;
Ok(path)
} else {
let path = find_thread_path_by_name_str(&config.codex_home, id_str).await?;
Ok(path)
}
} else {
Ok(None)
}