diff --git a/codex-rs/core/src/codex.rs b/codex-rs/core/src/codex.rs index fe875b2c..cae47cb3 100644 --- a/codex-rs/core/src/codex.rs +++ b/codex-rs/core/src/codex.rs @@ -88,7 +88,6 @@ use crate::protocol::ReviewDecision; use crate::protocol::ReviewOutputEvent; use crate::protocol::SandboxPolicy; use crate::protocol::SessionConfiguredEvent; -use crate::protocol::SessionRenamedEvent; use crate::protocol::StreamErrorEvent; use crate::protocol::Submission; use crate::protocol::TokenCountEvent; @@ -1508,16 +1507,6 @@ async fn submission_loop( }; sess.send_event(event).await; } - Op::SetSessionName { name } => { - // Persist a rename event and notify the client. We rely on the - // recorder's filtering to include this in the rollout. - let sub_id = sub.id.clone(); - let event = Event { - id: sub_id, - msg: EventMsg::SessionRenamed(SessionRenamedEvent { name }), - }; - sess.send_event(event).await; - } Op::Review { review_request } => { spawn_review_thread( sess.clone(), diff --git a/codex-rs/core/src/rollout/list.rs b/codex-rs/core/src/rollout/list.rs index 0276a91a..b27b3382 100644 --- a/codex-rs/core/src/rollout/list.rs +++ b/codex-rs/core/src/rollout/list.rs @@ -17,7 +17,6 @@ use super::SESSIONS_SUBDIR; use crate::protocol::EventMsg; use codex_protocol::protocol::RolloutItem; use codex_protocol::protocol::RolloutLine; -use codex_protocol::protocol::SessionRenamedEvent; use codex_protocol::protocol::SessionSource; /// Returned page of conversation summaries. @@ -42,8 +41,6 @@ pub struct ConversationItem { pub head: Vec, /// Last up to `TAIL_RECORD_LIMIT` JSONL response records parsed as JSON. pub tail: Vec, - /// Latest human-friendly session name, if any. - pub name: Option, /// RFC3339 timestamp string for when the session was created, if available. pub created_at: Option, /// RFC3339 timestamp string for the most recent response in the tail, if available. @@ -59,7 +56,6 @@ struct HeadTailSummary { source: Option, created_at: Option, updated_at: Option, - name: Option, } /// Hard cap to bound worst‑case work per request. @@ -226,7 +222,6 @@ async fn traverse_directories_for_paths( path, head, tail, - name: summary.name, created_at, updated_at, }); @@ -387,21 +382,14 @@ async fn read_head_and_tail( if matches!(ev, EventMsg::UserMessage(_)) { summary.saw_user_event = true; } - if let EventMsg::SessionRenamed(SessionRenamedEvent { name }) = ev { - summary.name = Some(name); - } } } } if tail_limit != 0 { - let (tail, updated_at, latest_name) = read_tail_records(path, tail_limit).await?; + let (tail, updated_at) = read_tail_records(path, tail_limit).await?; summary.tail = tail; summary.updated_at = updated_at; - // Prefer the most recent rename event discovered from the tail scan; fallback to any name seen in head. - if latest_name.is_some() { - summary.name = latest_name; - } } Ok(summary) } @@ -409,13 +397,13 @@ async fn read_head_and_tail( async fn read_tail_records( path: &Path, max_records: usize, -) -> io::Result<(Vec, Option, Option)> { +) -> io::Result<(Vec, Option)> { use std::io::SeekFrom; use tokio::io::AsyncReadExt; use tokio::io::AsyncSeekExt; if max_records == 0 { - return Ok((Vec::new(), None, None)); + return Ok((Vec::new(), None)); } const CHUNK_SIZE: usize = 8192; @@ -423,33 +411,28 @@ async fn read_tail_records( let mut file = tokio::fs::File::open(path).await?; let mut pos = file.seek(SeekFrom::End(0)).await?; if pos == 0 { - return Ok((Vec::new(), None, None)); + return Ok((Vec::new(), None)); } let mut buffer: Vec = Vec::new(); let mut latest_timestamp: Option = None; - let mut latest_name: Option = None; loop { let slice_start = match (pos > 0, buffer.iter().position(|&b| b == b'\n')) { (true, Some(idx)) => idx + 1, _ => 0, }; - let (tail, newest_ts, name_opt) = - collect_last_response_values(&buffer[slice_start..], max_records); + let (tail, newest_ts) = collect_last_response_values(&buffer[slice_start..], max_records); if latest_timestamp.is_none() { latest_timestamp = newest_ts.clone(); } - if latest_name.is_none() { - latest_name = name_opt.clone(); - } if tail.len() >= max_records || pos == 0 { - return Ok((tail, latest_timestamp.or(newest_ts), latest_name)); + return Ok((tail, latest_timestamp.or(newest_ts))); } let read_size = CHUNK_SIZE.min(pos as usize); if read_size == 0 { - return Ok((tail, latest_timestamp.or(newest_ts), latest_name)); + return Ok((tail, latest_timestamp.or(newest_ts))); } pos -= read_size as u64; file.seek(SeekFrom::Start(pos)).await?; @@ -463,17 +446,16 @@ async fn read_tail_records( fn collect_last_response_values( buffer: &[u8], max_records: usize, -) -> (Vec, Option, Option) { +) -> (Vec, Option) { use std::borrow::Cow; if buffer.is_empty() || max_records == 0 { - return (Vec::new(), None, None); + return (Vec::new(), None); } let text: Cow<'_, str> = String::from_utf8_lossy(buffer); let mut collected_rev: Vec = Vec::new(); let mut latest_timestamp: Option = None; - let mut latest_name: Option = None; for line in text.lines().rev() { let trimmed = line.trim(); if trimmed.is_empty() { @@ -482,30 +464,20 @@ fn collect_last_response_values( let parsed: serde_json::Result = serde_json::from_str(trimmed); let Ok(rollout_line) = parsed else { continue }; let RolloutLine { timestamp, item } = rollout_line; - match item { - RolloutItem::ResponseItem(item) => { - if let Ok(val) = serde_json::to_value(&item) { - if latest_timestamp.is_none() { - latest_timestamp = Some(timestamp.clone()); - } - collected_rev.push(val); - if collected_rev.len() == max_records { - break; - } - } + if let RolloutItem::ResponseItem(item) = item + && let Ok(val) = serde_json::to_value(&item) + { + if latest_timestamp.is_none() { + latest_timestamp = Some(timestamp.clone()); } - RolloutItem::EventMsg(ev) => { - if latest_name.is_none() - && let EventMsg::SessionRenamed(SessionRenamedEvent { name }) = ev - { - latest_name = Some(name); - } + collected_rev.push(val); + if collected_rev.len() == max_records { + break; } - _ => {} } } collected_rev.reverse(); - (collected_rev, latest_timestamp, latest_name) + (collected_rev, latest_timestamp) } /// Locate a recorded conversation rollout file by its UUID string using the existing diff --git a/codex-rs/core/src/rollout/policy.rs b/codex-rs/core/src/rollout/policy.rs index 3ff25e59..8fc39e79 100644 --- a/codex-rs/core/src/rollout/policy.rs +++ b/codex-rs/core/src/rollout/policy.rs @@ -39,7 +39,6 @@ pub(crate) fn should_persist_event_msg(ev: &EventMsg) -> bool { | EventMsg::AgentMessage(_) | EventMsg::AgentReasoning(_) | EventMsg::AgentReasoningRawContent(_) - | EventMsg::SessionRenamed(_) | EventMsg::TokenCount(_) | EventMsg::EnteredReviewMode(_) | EventMsg::ExitedReviewMode(_) diff --git a/codex-rs/core/src/rollout/tests.rs b/codex-rs/core/src/rollout/tests.rs index f3e2c82f..b1f34e3a 100644 --- a/codex-rs/core/src/rollout/tests.rs +++ b/codex-rs/core/src/rollout/tests.rs @@ -196,7 +196,6 @@ async fn test_list_conversations_latest_first() { path: p1, head: head_3, tail: Vec::new(), - name: None, created_at: Some("2025-01-03T12-00-00".into()), updated_at: Some("2025-01-03T12-00-00".into()), }, @@ -204,7 +203,6 @@ async fn test_list_conversations_latest_first() { path: p2, head: head_2, tail: Vec::new(), - name: None, created_at: Some("2025-01-02T12-00-00".into()), updated_at: Some("2025-01-02T12-00-00".into()), }, @@ -212,7 +210,6 @@ async fn test_list_conversations_latest_first() { path: p3, head: head_1, tail: Vec::new(), - name: None, created_at: Some("2025-01-01T12-00-00".into()), updated_at: Some("2025-01-01T12-00-00".into()), }, @@ -320,7 +317,6 @@ async fn test_pagination_cursor() { path: p5, head: head_5, tail: Vec::new(), - name: None, created_at: Some("2025-03-05T09-00-00".into()), updated_at: Some("2025-03-05T09-00-00".into()), }, @@ -328,7 +324,6 @@ async fn test_pagination_cursor() { path: p4, head: head_4, tail: Vec::new(), - name: None, created_at: Some("2025-03-04T09-00-00".into()), updated_at: Some("2025-03-04T09-00-00".into()), }, @@ -385,7 +380,6 @@ async fn test_pagination_cursor() { path: p3, head: head_3, tail: Vec::new(), - name: None, created_at: Some("2025-03-03T09-00-00".into()), updated_at: Some("2025-03-03T09-00-00".into()), }, @@ -393,7 +387,6 @@ async fn test_pagination_cursor() { path: p2, head: head_2, tail: Vec::new(), - name: None, created_at: Some("2025-03-02T09-00-00".into()), updated_at: Some("2025-03-02T09-00-00".into()), }, @@ -434,7 +427,6 @@ async fn test_pagination_cursor() { path: p1, head: head_1, tail: Vec::new(), - name: None, created_at: Some("2025-03-01T09-00-00".into()), updated_at: Some("2025-03-01T09-00-00".into()), }], @@ -483,7 +475,6 @@ async fn test_get_conversation_contents() { path: expected_path, head: expected_head, tail: Vec::new(), - name: None, created_at: Some(ts.into()), updated_at: Some(ts.into()), }], @@ -832,7 +823,6 @@ async fn test_stable_ordering_same_second_pagination() { path: p3, head: head(u3), tail: Vec::new(), - name: None, created_at: Some(ts.to_string()), updated_at: Some(ts.to_string()), }, @@ -840,7 +830,6 @@ async fn test_stable_ordering_same_second_pagination() { path: p2, head: head(u2), tail: Vec::new(), - name: None, created_at: Some(ts.to_string()), updated_at: Some(ts.to_string()), }, @@ -871,7 +860,6 @@ async fn test_stable_ordering_same_second_pagination() { path: p1, head: head(u1), tail: Vec::new(), - name: None, created_at: Some(ts.to_string()), updated_at: Some(ts.to_string()), }], diff --git a/codex-rs/exec/src/event_processor_with_human_output.rs b/codex-rs/exec/src/event_processor_with_human_output.rs index 465be95c..f9aa3f85 100644 --- a/codex-rs/exec/src/event_processor_with_human_output.rs +++ b/codex-rs/exec/src/event_processor_with_human_output.rs @@ -511,7 +511,6 @@ impl EventProcessor for EventProcessorWithHumanOutput { }, EventMsg::ShutdownComplete => return CodexStatus::Shutdown, EventMsg::ConversationPath(_) => {} - EventMsg::SessionRenamed(_) => {} EventMsg::UserMessage(_) => {} EventMsg::EnteredReviewMode(_) => {} EventMsg::ExitedReviewMode(_) => {} diff --git a/codex-rs/mcp-server/src/codex_tool_runner.rs b/codex-rs/mcp-server/src/codex_tool_runner.rs index a5a3f4f7..f09dc98c 100644 --- a/codex-rs/mcp-server/src/codex_tool_runner.rs +++ b/codex-rs/mcp-server/src/codex_tool_runner.rs @@ -279,7 +279,6 @@ async fn run_codex_tool_session_inner( | EventMsg::TurnAborted(_) | EventMsg::ConversationPath(_) | EventMsg::UserMessage(_) - | EventMsg::SessionRenamed(_) | EventMsg::ShutdownComplete | EventMsg::ViewImageToolCall(_) | EventMsg::EnteredReviewMode(_) diff --git a/codex-rs/protocol/src/protocol.rs b/codex-rs/protocol/src/protocol.rs index 100de2c7..1ae32e51 100644 --- a/codex-rs/protocol/src/protocol.rs +++ b/codex-rs/protocol/src/protocol.rs @@ -171,11 +171,6 @@ pub enum Op { /// to generate a summary which will be returned as an AgentMessage event. Compact, - /// Set a human-friendly name for the current session. - /// The agent will persist this to the rollout as an event so that UIs can - /// surface it when listing sessions. - SetSessionName { name: String }, - /// Request a code review from the agent. Review { review_request: ReviewRequest }, @@ -463,9 +458,6 @@ pub enum EventMsg { /// Signaled when the model begins a new reasoning summary section (e.g., a new titled block). AgentReasoningSectionBreak(AgentReasoningSectionBreakEvent), - /// Session was given a human-friendly name by the user. - SessionRenamed(SessionRenamedEvent), - /// Ack the client's configure message. SessionConfigured(SessionConfiguredEvent), @@ -903,11 +895,6 @@ pub struct WebSearchEndEvent { pub query: String, } -#[derive(Debug, Clone, Deserialize, Serialize, TS)] -pub struct SessionRenamedEvent { - pub name: String, -} - /// Response payload for `Op::GetHistory` containing the current session's /// in-memory transcript. #[derive(Debug, Clone, Deserialize, Serialize, TS)] diff --git a/codex-rs/tui/src/app.rs b/codex-rs/tui/src/app.rs index 8ff57e6a..cb3dea5e 100644 --- a/codex-rs/tui/src/app.rs +++ b/codex-rs/tui/src/app.rs @@ -381,9 +381,6 @@ impl App { AppEvent::OpenReviewCustomPrompt => { self.chat_widget.show_review_custom_prompt(); } - AppEvent::SetSessionName(name) => { - self.chat_widget.begin_set_session_name(name); - } AppEvent::FullScreenApprovalRequest(request) => match request { ApprovalRequest::ApplyPatch { cwd, changes, .. } => { let _ = tui.enter_alt_screen(); diff --git a/codex-rs/tui/src/app_event.rs b/codex-rs/tui/src/app_event.rs index e0bdd039..9d79c8ae 100644 --- a/codex-rs/tui/src/app_event.rs +++ b/codex-rs/tui/src/app_event.rs @@ -85,9 +85,6 @@ pub(crate) enum AppEvent { /// Open the custom prompt option from the review popup. OpenReviewCustomPrompt, - /// Begin setting a human-readable name for the current session. - SetSessionName(String), - /// Open the approval popup. FullScreenApprovalRequest(ApprovalRequest), } diff --git a/codex-rs/tui/src/bottom_pane/mod.rs b/codex-rs/tui/src/bottom_pane/mod.rs index 4eca199b..db13a041 100644 --- a/codex-rs/tui/src/bottom_pane/mod.rs +++ b/codex-rs/tui/src/bottom_pane/mod.rs @@ -25,7 +25,7 @@ pub mod custom_prompt_view; mod file_search_popup; mod footer; mod list_selection_view; -pub mod prompt_args; +mod prompt_args; pub(crate) use list_selection_view::SelectionViewParams; mod paste_burst; pub mod popup_consts; diff --git a/codex-rs/tui/src/chatwidget.rs b/codex-rs/tui/src/chatwidget.rs index 8da2ca63..973b0e3b 100644 --- a/codex-rs/tui/src/chatwidget.rs +++ b/codex-rs/tui/src/chatwidget.rs @@ -1104,7 +1104,6 @@ impl ChatWidget { return; } match cmd { - SlashCommand::Name => self.open_name_popup(), SlashCommand::New => { self.app_event_tx.send(AppEvent::NewSession); } @@ -1252,29 +1251,6 @@ impl ChatWidget { return; } - // Intercept '/name ' as a local rename command (no images allowed). - if image_paths.is_empty() - && let Some((cmd, rest)) = crate::bottom_pane::prompt_args::parse_slash_name(&text) - && cmd == "name" - { - let name = rest.trim(); - if name.is_empty() { - // Provide a brief usage hint. - self.add_to_history(history_cell::new_info_event( - "Usage: /name ".to_string(), - None, - )); - self.request_redraw(); - } else { - // Send the rename op; persistence and ack come as an event. - let name_str = name.to_string(); - self.codex_op_tx - .send(Op::SetSessionName { name: name_str }) - .unwrap_or_else(|e| tracing::error!("failed to send SetSessionName op: {e}")); - } - return; - } - self.capture_ghost_snapshot(); let mut items: Vec = Vec::new(); @@ -1467,13 +1443,6 @@ impl ChatWidget { self.app_event_tx .send(crate::app_event::AppEvent::ConversationHistory(ev)); } - EventMsg::SessionRenamed(ev) => { - self.add_to_history(history_cell::new_info_event( - format!("Named this chat: {}", ev.name), - None, - )); - self.request_redraw(); - } EventMsg::EnteredReviewMode(review_request) => { self.on_entered_review_mode(review_request) } @@ -2112,33 +2081,6 @@ impl ChatWidget { self.bottom_pane.show_view(Box::new(view)); } - pub(crate) fn open_name_popup(&mut self) { - let tx = self.app_event_tx.clone(); - let view = CustomPromptView::new( - "Name this chat".to_string(), - "Type a name and press Enter".to_string(), - None, - Box::new(move |name: String| { - let trimmed = name.trim().to_string(); - if trimmed.is_empty() { - return; - } - tx.send(AppEvent::SetSessionName(trimmed)); - }), - ); - self.bottom_pane.show_view(Box::new(view)); - } - - pub(crate) fn begin_set_session_name(&mut self, name: String) { - let trimmed = name.trim().to_string(); - if trimmed.is_empty() { - return; - } - self.codex_op_tx - .send(Op::SetSessionName { name: trimmed }) - .unwrap_or_else(|e| tracing::error!("failed to send SetSessionName op: {e}")); - } - /// Programmatically submit a user text message as if typed in the /// composer. The text will be added to conversation history and sent to /// the agent. diff --git a/codex-rs/tui/src/resume_picker.rs b/codex-rs/tui/src/resume_picker.rs index 1ef580ad..eb2a9cd4 100644 --- a/codex-rs/tui/src/resume_picker.rs +++ b/codex-rs/tui/src/resume_picker.rs @@ -167,7 +167,6 @@ struct PickerState { next_search_token: usize, page_loader: PageLoader, view_rows: Option, - // No additional per-path state; names are embedded in rollouts. } struct PaginationState { @@ -587,14 +586,9 @@ fn head_to_row(item: &ConversationItem) -> Row { .and_then(parse_timestamp_str) .or(created_at); - let preview = item - .name - .clone() - .or_else(|| { - preview_from_head(&item.head) - .map(|s| s.trim().to_string()) - .filter(|s| !s.is_empty()) - }) + let preview = preview_from_head(&item.head) + .map(|s| s.trim().to_string()) + .filter(|s| !s.is_empty()) .unwrap_or_else(|| String::from("(no message yet)")); Row { @@ -964,7 +958,6 @@ mod tests { path: PathBuf::from(path), head: head_with_ts_and_user_text(ts, &[preview]), tail: Vec::new(), - name: None, created_at: Some(ts.to_string()), updated_at: Some(ts.to_string()), } @@ -1027,7 +1020,6 @@ mod tests { path: PathBuf::from("/tmp/a.jsonl"), head: head_with_ts_and_user_text("2025-01-01T00:00:00Z", &["A"]), tail: Vec::new(), - name: None, created_at: Some("2025-01-01T00:00:00Z".into()), updated_at: Some("2025-01-01T00:00:00Z".into()), }; @@ -1035,7 +1027,6 @@ mod tests { path: PathBuf::from("/tmp/b.jsonl"), head: head_with_ts_and_user_text("2025-01-02T00:00:00Z", &["B"]), tail: Vec::new(), - name: None, created_at: Some("2025-01-02T00:00:00Z".into()), updated_at: Some("2025-01-02T00:00:00Z".into()), }; @@ -1064,7 +1055,6 @@ mod tests { path: PathBuf::from("/tmp/a.jsonl"), head, tail, - name: None, created_at: Some("2025-01-01T00:00:00Z".into()), updated_at: Some("2025-01-01T01:00:00Z".into()), }; diff --git a/codex-rs/tui/src/slash_command.rs b/codex-rs/tui/src/slash_command.rs index 92afe247..14604a73 100644 --- a/codex-rs/tui/src/slash_command.rs +++ b/codex-rs/tui/src/slash_command.rs @@ -15,7 +15,6 @@ pub enum SlashCommand { Model, Approvals, Review, - Name, New, Init, Compact, @@ -34,7 +33,6 @@ impl SlashCommand { /// User-visible description shown in the popup. pub fn description(self) -> &'static str { match self { - SlashCommand::Name => "set a name for this chat", SlashCommand::New => "start a new chat during a conversation", SlashCommand::Init => "create an AGENTS.md file with instructions for Codex", SlashCommand::Compact => "summarize conversation to prevent hitting the context limit", @@ -62,8 +60,6 @@ impl SlashCommand { /// Whether this command can be run while a task is in progress. pub fn available_during_task(self) -> bool { match self { - // Naming is a local UI action; allow during tasks. - SlashCommand::Name => true, SlashCommand::New | SlashCommand::Init | SlashCommand::Compact