mirror of
https://github.com/openai/codex.git
synced 2026-11-09 20:50:33 +00:00
chore: unify conversation with thread name (#8830)
Done and verified by Codex + refactor feature of RustRover
This commit is contained in:
+27
-39
@@ -40,7 +40,7 @@ use crate::tui::scrolling::TranscriptScroll;
|
||||
use crate::update_action::UpdateAction;
|
||||
use codex_ansi_escape::ansi_escape_line;
|
||||
use codex_core::AuthManager;
|
||||
use codex_core::ConversationManager;
|
||||
use codex_core::ThreadManager;
|
||||
use codex_core::config::Config;
|
||||
use codex_core::config::edit::ConfigEditsBuilder;
|
||||
#[cfg(target_os = "windows")]
|
||||
@@ -56,7 +56,7 @@ use codex_core::protocol::SessionSource;
|
||||
use codex_core::protocol::SkillErrorInfo;
|
||||
use codex_core::protocol::TokenUsage;
|
||||
use codex_core::terminal::terminal_info;
|
||||
use codex_protocol::ConversationId;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::openai_models::ModelPreset;
|
||||
use codex_protocol::openai_models::ModelUpgrade;
|
||||
use codex_protocol::openai_models::ReasoningEffort as ReasoningEffortConfig;
|
||||
@@ -91,7 +91,7 @@ use crate::history_cell::UpdateAvailableHistoryCell;
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AppExitInfo {
|
||||
pub token_usage: TokenUsage,
|
||||
pub conversation_id: Option<ConversationId>,
|
||||
pub conversation_id: Option<ThreadId>,
|
||||
pub update_action: Option<UpdateAction>,
|
||||
/// ANSI-styled transcript lines to print after the TUI exits.
|
||||
///
|
||||
@@ -105,7 +105,7 @@ impl From<AppExitInfo> for codex_tui::AppExitInfo {
|
||||
fn from(info: AppExitInfo) -> Self {
|
||||
codex_tui::AppExitInfo {
|
||||
token_usage: info.token_usage,
|
||||
conversation_id: info.conversation_id,
|
||||
thread_id: info.conversation_id,
|
||||
update_action: info.update_action.map(Into::into),
|
||||
}
|
||||
}
|
||||
@@ -113,7 +113,7 @@ impl From<AppExitInfo> for codex_tui::AppExitInfo {
|
||||
|
||||
fn session_summary(
|
||||
token_usage: TokenUsage,
|
||||
conversation_id: Option<ConversationId>,
|
||||
conversation_id: Option<ThreadId>,
|
||||
) -> Option<SessionSummary> {
|
||||
if token_usage.is_zero() {
|
||||
return None;
|
||||
@@ -320,7 +320,7 @@ async fn handle_model_migration_prompt_if_needed(
|
||||
}
|
||||
|
||||
pub(crate) struct App {
|
||||
pub(crate) server: Arc<ConversationManager>,
|
||||
pub(crate) server: Arc<ThreadManager>,
|
||||
pub(crate) app_event_tx: AppEventSender,
|
||||
pub(crate) chat_widget: ChatWidget,
|
||||
pub(crate) auth_manager: Arc<AuthManager>,
|
||||
@@ -387,7 +387,7 @@ impl App {
|
||||
if let Some(conversation_id) = self.chat_widget.conversation_id() {
|
||||
self.suppress_shutdown_complete = true;
|
||||
self.chat_widget.submit_op(Op::Shutdown);
|
||||
self.server.remove_conversation(&conversation_id).await;
|
||||
self.server.remove_thread(&conversation_id).await;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -407,11 +407,8 @@ impl App {
|
||||
let (app_event_tx, mut app_event_rx) = unbounded_channel();
|
||||
let app_event_tx = AppEventSender::new(app_event_tx);
|
||||
|
||||
let conversation_manager = Arc::new(ConversationManager::new(
|
||||
auth_manager.clone(),
|
||||
SessionSource::Cli,
|
||||
));
|
||||
let mut model = conversation_manager
|
||||
let thread_manager = Arc::new(ThreadManager::new(auth_manager.clone(), SessionSource::Cli));
|
||||
let mut model = thread_manager
|
||||
.get_models_manager()
|
||||
.get_model(&config.model, &config)
|
||||
.await;
|
||||
@@ -420,7 +417,7 @@ impl App {
|
||||
&mut config,
|
||||
model.as_str(),
|
||||
&app_event_tx,
|
||||
conversation_manager.get_models_manager(),
|
||||
thread_manager.get_models_manager(),
|
||||
)
|
||||
.await;
|
||||
if let Some(exit_info) = exit_info {
|
||||
@@ -441,20 +438,16 @@ impl App {
|
||||
initial_images: initial_images.clone(),
|
||||
enhanced_keys_supported,
|
||||
auth_manager: auth_manager.clone(),
|
||||
models_manager: conversation_manager.get_models_manager(),
|
||||
models_manager: thread_manager.get_models_manager(),
|
||||
feedback: feedback.clone(),
|
||||
is_first_run,
|
||||
model: model.clone(),
|
||||
};
|
||||
ChatWidget::new(init, conversation_manager.clone())
|
||||
ChatWidget::new(init, thread_manager.clone())
|
||||
}
|
||||
ResumeSelection::Resume(path) => {
|
||||
let resumed = conversation_manager
|
||||
.resume_conversation_from_rollout(
|
||||
config.clone(),
|
||||
path.clone(),
|
||||
auth_manager.clone(),
|
||||
)
|
||||
let resumed = thread_manager
|
||||
.resume_thread_from_rollout(config.clone(), path.clone(), auth_manager.clone())
|
||||
.await
|
||||
.wrap_err_with(|| {
|
||||
format!("Failed to resume session from {}", path.display())
|
||||
@@ -467,16 +460,12 @@ impl App {
|
||||
initial_images: initial_images.clone(),
|
||||
enhanced_keys_supported,
|
||||
auth_manager: auth_manager.clone(),
|
||||
models_manager: conversation_manager.get_models_manager(),
|
||||
models_manager: thread_manager.get_models_manager(),
|
||||
feedback: feedback.clone(),
|
||||
is_first_run,
|
||||
model: model.clone(),
|
||||
};
|
||||
ChatWidget::new_from_existing(
|
||||
init,
|
||||
resumed.conversation,
|
||||
resumed.session_configured,
|
||||
)
|
||||
ChatWidget::new_from_existing(init, resumed.thread, resumed.session_configured)
|
||||
}
|
||||
};
|
||||
|
||||
@@ -503,7 +492,7 @@ impl App {
|
||||
let copy_selection_shortcut = crate::transcript_copy_ui::detect_copy_selection_shortcut();
|
||||
|
||||
let mut app = Self {
|
||||
server: conversation_manager.clone(),
|
||||
server: thread_manager.clone(),
|
||||
app_event_tx,
|
||||
chat_widget,
|
||||
auth_manager: auth_manager.clone(),
|
||||
@@ -1400,7 +1389,7 @@ impl App {
|
||||
);
|
||||
match self
|
||||
.server
|
||||
.resume_conversation_from_rollout(
|
||||
.resume_thread_from_rollout(
|
||||
self.config.clone(),
|
||||
path.clone(),
|
||||
self.auth_manager.clone(),
|
||||
@@ -1424,7 +1413,7 @@ impl App {
|
||||
};
|
||||
self.chat_widget = ChatWidget::new_from_existing(
|
||||
init,
|
||||
resumed.conversation,
|
||||
resumed.thread,
|
||||
resumed.session_configured,
|
||||
);
|
||||
if let Some(summary) = summary {
|
||||
@@ -2087,14 +2076,14 @@ mod tests {
|
||||
use crate::tui::scrolling::TranscriptLineMeta;
|
||||
use codex_core::AuthManager;
|
||||
use codex_core::CodexAuth;
|
||||
use codex_core::ConversationManager;
|
||||
use codex_core::ThreadManager;
|
||||
use codex_core::config::ConfigBuilder;
|
||||
use codex_core::protocol::AskForApproval;
|
||||
use codex_core::protocol::Event;
|
||||
use codex_core::protocol::EventMsg;
|
||||
use codex_core::protocol::SandboxPolicy;
|
||||
use codex_core::protocol::SessionConfiguredEvent;
|
||||
use codex_protocol::ConversationId;
|
||||
use codex_protocol::ThreadId;
|
||||
use insta::assert_snapshot;
|
||||
use pretty_assertions::assert_eq;
|
||||
use ratatui::prelude::Line;
|
||||
@@ -2107,7 +2096,7 @@ mod tests {
|
||||
let (chat_widget, app_event_tx, _rx, _op_rx) = make_chatwidget_manual_with_sender().await;
|
||||
let config = chat_widget.config_ref().clone();
|
||||
let current_model = "gpt-5.2-codex".to_string();
|
||||
let server = Arc::new(ConversationManager::with_models_provider(
|
||||
let server = Arc::new(ThreadManager::with_models_provider(
|
||||
CodexAuth::from_api_key("Test API Key"),
|
||||
config.model_provider.clone(),
|
||||
));
|
||||
@@ -2159,7 +2148,7 @@ mod tests {
|
||||
let (chat_widget, app_event_tx, rx, op_rx) = make_chatwidget_manual_with_sender().await;
|
||||
let config = chat_widget.config_ref().clone();
|
||||
let current_model = "gpt-5.2-codex".to_string();
|
||||
let server = Arc::new(ConversationManager::with_models_provider(
|
||||
let server = Arc::new(ThreadManager::with_models_provider(
|
||||
CodexAuth::from_api_key("Test API Key"),
|
||||
config.model_provider.clone(),
|
||||
));
|
||||
@@ -2404,7 +2393,7 @@ mod tests {
|
||||
|
||||
let make_header = |is_first| {
|
||||
let event = SessionConfiguredEvent {
|
||||
session_id: ConversationId::new(),
|
||||
session_id: ThreadId::new(),
|
||||
model: "gpt-test".to_string(),
|
||||
model_provider_id: "test-provider".to_string(),
|
||||
approval_policy: AskForApproval::Never,
|
||||
@@ -2442,7 +2431,7 @@ mod tests {
|
||||
|
||||
assert_eq!(user_count(&app.transcript_cells), 2);
|
||||
|
||||
app.backtrack.base_id = Some(ConversationId::new());
|
||||
app.backtrack.base_id = Some(ThreadId::new());
|
||||
app.backtrack.primed = true;
|
||||
app.backtrack.nth_user_message = user_count(&app.transcript_cells).saturating_sub(1);
|
||||
|
||||
@@ -2697,7 +2686,7 @@ mod tests {
|
||||
async fn new_session_requests_shutdown_for_previous_conversation() {
|
||||
let (mut app, mut app_event_rx, mut op_rx) = make_test_app_with_channels().await;
|
||||
|
||||
let conversation_id = ConversationId::new();
|
||||
let conversation_id = ThreadId::new();
|
||||
let event = SessionConfiguredEvent {
|
||||
session_id: conversation_id,
|
||||
model: "gpt-test".to_string(),
|
||||
@@ -2763,8 +2752,7 @@ mod tests {
|
||||
total_tokens: 12,
|
||||
..Default::default()
|
||||
};
|
||||
let conversation =
|
||||
ConversationId::from_string("123e4567-e89b-12d3-a456-426614174000").unwrap();
|
||||
let conversation = ThreadId::from_string("123e4567-e89b-12d3-a456-426614174000").unwrap();
|
||||
|
||||
let summary = session_summary(usage, Some(conversation)).expect("summary");
|
||||
assert_eq!(
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::pager_overlay::Overlay;
|
||||
use crate::tui;
|
||||
use crate::tui::TuiEvent;
|
||||
use codex_core::protocol::ConversationPathResponseEvent;
|
||||
use codex_protocol::ConversationId;
|
||||
use codex_protocol::ThreadId;
|
||||
use color_eyre::eyre::Result;
|
||||
use crossterm::event::KeyCode;
|
||||
use crossterm::event::KeyEvent;
|
||||
@@ -21,13 +21,13 @@ pub(crate) struct BacktrackState {
|
||||
/// True when Esc has primed backtrack mode in the main view.
|
||||
pub(crate) primed: bool,
|
||||
/// Session id of the base conversation to fork from.
|
||||
pub(crate) base_id: Option<ConversationId>,
|
||||
pub(crate) base_id: Option<ThreadId>,
|
||||
/// Index in the transcript of the last user message.
|
||||
pub(crate) nth_user_message: usize,
|
||||
/// True when the transcript overlay is showing a backtrack preview.
|
||||
pub(crate) overlay_preview_active: bool,
|
||||
/// Pending fork request: (base_id, nth_user_message, prefill).
|
||||
pub(crate) pending: Option<(ConversationId, usize, String)>,
|
||||
pub(crate) pending: Option<(ThreadId, usize, String)>,
|
||||
}
|
||||
|
||||
impl App {
|
||||
@@ -99,7 +99,7 @@ impl App {
|
||||
pub(crate) fn request_backtrack(
|
||||
&mut self,
|
||||
prefill: String,
|
||||
base_id: ConversationId,
|
||||
base_id: ThreadId,
|
||||
nth_user_message: usize,
|
||||
) {
|
||||
self.backtrack.pending = Some((base_id, nth_user_message, prefill));
|
||||
@@ -308,7 +308,7 @@ impl App {
|
||||
}
|
||||
|
||||
/// Handle a ConversationHistory response while a backtrack is pending.
|
||||
/// If it matches the primed base session, fork and switch to the new conversation.
|
||||
/// If it matches the primed base session, fork and switch to the new thread.
|
||||
pub(crate) async fn on_conversation_history_for_backtrack(
|
||||
&mut self,
|
||||
tui: &mut tui::Tui,
|
||||
@@ -324,7 +324,7 @@ impl App {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Fork the conversation using provided history and switch UI/state accordingly.
|
||||
/// Fork the thread using provided history and switch UI/state accordingly.
|
||||
async fn fork_and_switch_to_new_conversation(
|
||||
&mut self,
|
||||
tui: &mut tui::Tui,
|
||||
@@ -345,28 +345,26 @@ impl App {
|
||||
}
|
||||
}
|
||||
|
||||
/// Thin wrapper around ConversationManager::fork_conversation.
|
||||
/// Thin wrapper around ThreadManager::fork_thread.
|
||||
async fn perform_fork(
|
||||
&self,
|
||||
path: PathBuf,
|
||||
nth_user_message: usize,
|
||||
cfg: codex_core::config::Config,
|
||||
) -> codex_core::error::Result<codex_core::NewConversation> {
|
||||
self.server
|
||||
.fork_conversation(nth_user_message, cfg, path)
|
||||
.await
|
||||
) -> codex_core::error::Result<codex_core::NewThread> {
|
||||
self.server.fork_thread(nth_user_message, cfg, path).await
|
||||
}
|
||||
|
||||
/// Install a forked conversation into the ChatWidget and update UI to reflect selection.
|
||||
/// Install a forked thread into the ChatWidget and update UI to reflect selection.
|
||||
fn install_forked_conversation(
|
||||
&mut self,
|
||||
tui: &mut tui::Tui,
|
||||
cfg: codex_core::config::Config,
|
||||
new_conv: codex_core::NewConversation,
|
||||
new_conv: codex_core::NewThread,
|
||||
nth_user_message: usize,
|
||||
prefill: &str,
|
||||
) {
|
||||
let conv = new_conv.conversation;
|
||||
let thread = new_conv.thread;
|
||||
let session_configured = new_conv.session_configured;
|
||||
let init = crate::chatwidget::ChatWidgetInit {
|
||||
config: cfg,
|
||||
@@ -382,7 +380,7 @@ impl App {
|
||||
is_first_run: false,
|
||||
};
|
||||
self.chat_widget =
|
||||
crate::chatwidget::ChatWidget::new_from_existing(init, conv, session_configured);
|
||||
crate::chatwidget::ChatWidget::new_from_existing(init, thread, session_configured);
|
||||
// Trim transcript up to the selected user message and re-render it.
|
||||
self.trim_transcript_for_backtrack(nth_user_message);
|
||||
self.render_transcript_once(tui);
|
||||
|
||||
@@ -61,7 +61,7 @@ use codex_core::protocol::WarningEvent;
|
||||
use codex_core::protocol::WebSearchBeginEvent;
|
||||
use codex_core::protocol::WebSearchEndEvent;
|
||||
use codex_core::skills::model::SkillMetadata;
|
||||
use codex_protocol::ConversationId;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::account::PlanType;
|
||||
use codex_protocol::approvals::ElicitationRequestEvent;
|
||||
use codex_protocol::parse_command::ParsedCommand;
|
||||
@@ -131,7 +131,7 @@ use codex_common::approval_presets::ApprovalPreset;
|
||||
use codex_common::approval_presets::builtin_approval_presets;
|
||||
use codex_core::AuthManager;
|
||||
use codex_core::CodexAuth;
|
||||
use codex_core::ConversationManager;
|
||||
use codex_core::ThreadManager;
|
||||
use codex_core::protocol::AskForApproval;
|
||||
use codex_core::protocol::SandboxPolicy;
|
||||
use codex_file_search::FileMatch;
|
||||
@@ -311,7 +311,7 @@ pub(crate) struct ChatWidget {
|
||||
current_status_header: String,
|
||||
// Previous status header to restore after a transient stream retry.
|
||||
retry_status_header: Option<String>,
|
||||
conversation_id: Option<ConversationId>,
|
||||
conversation_id: Option<ThreadId>,
|
||||
frame_requester: FrameRequester,
|
||||
// Whether to include the initial welcome banner on session configured
|
||||
show_welcome_banner: bool,
|
||||
@@ -1264,10 +1264,7 @@ impl ChatWidget {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new(
|
||||
common: ChatWidgetInit,
|
||||
conversation_manager: Arc<ConversationManager>,
|
||||
) -> Self {
|
||||
pub(crate) fn new(common: ChatWidgetInit, thread_manager: Arc<ThreadManager>) -> Self {
|
||||
let ChatWidgetInit {
|
||||
config,
|
||||
frame_requester,
|
||||
@@ -1285,7 +1282,7 @@ impl ChatWidget {
|
||||
config.model = Some(model.clone());
|
||||
let mut rng = rand::rng();
|
||||
let placeholder = EXAMPLE_PROMPTS[rng.random_range(0..EXAMPLE_PROMPTS.len())].to_string();
|
||||
let codex_op_tx = spawn_agent(config.clone(), app_event_tx.clone(), conversation_manager);
|
||||
let codex_op_tx = spawn_agent(config.clone(), app_event_tx.clone(), thread_manager);
|
||||
|
||||
let mut widget = Self {
|
||||
app_event_tx: app_event_tx.clone(),
|
||||
@@ -1349,7 +1346,7 @@ impl ChatWidget {
|
||||
/// Create a ChatWidget attached to an existing conversation (e.g., a fork).
|
||||
pub(crate) fn new_from_existing(
|
||||
common: ChatWidgetInit,
|
||||
conversation: std::sync::Arc<codex_core::CodexConversation>,
|
||||
conversation: std::sync::Arc<codex_core::CodexThread>,
|
||||
session_configured: codex_core::protocol::SessionConfiguredEvent,
|
||||
) -> Self {
|
||||
let ChatWidgetInit {
|
||||
@@ -3366,7 +3363,7 @@ impl ChatWidget {
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub(crate) fn conversation_id(&self) -> Option<ConversationId> {
|
||||
pub(crate) fn conversation_id(&self) -> Option<ThreadId> {
|
||||
self.conversation_id
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use codex_core::CodexConversation;
|
||||
use codex_core::ConversationManager;
|
||||
use codex_core::NewConversation;
|
||||
use codex_core::CodexThread;
|
||||
use codex_core::NewThread;
|
||||
use codex_core::ThreadManager;
|
||||
use codex_core::config::Config;
|
||||
use codex_core::protocol::Event;
|
||||
use codex_core::protocol::EventMsg;
|
||||
@@ -18,17 +18,17 @@ use crate::app_event_sender::AppEventSender;
|
||||
pub(crate) fn spawn_agent(
|
||||
config: Config,
|
||||
app_event_tx: AppEventSender,
|
||||
server: Arc<ConversationManager>,
|
||||
server: Arc<ThreadManager>,
|
||||
) -> UnboundedSender<Op> {
|
||||
let (codex_op_tx, mut codex_op_rx) = unbounded_channel::<Op>();
|
||||
|
||||
let app_event_tx_clone = app_event_tx;
|
||||
tokio::spawn(async move {
|
||||
let NewConversation {
|
||||
conversation_id: _,
|
||||
conversation,
|
||||
let NewThread {
|
||||
thread,
|
||||
session_configured,
|
||||
} = match server.new_conversation(config).await {
|
||||
thread_id: _,
|
||||
} = match server.start_thread(config).await {
|
||||
Ok(v) => v,
|
||||
#[allow(clippy::print_stderr)]
|
||||
Err(err) => {
|
||||
@@ -52,17 +52,17 @@ pub(crate) fn spawn_agent(
|
||||
};
|
||||
app_event_tx_clone.send(AppEvent::CodexEvent(ev));
|
||||
|
||||
let conversation_clone = conversation.clone();
|
||||
let thread_clone = thread.clone();
|
||||
tokio::spawn(async move {
|
||||
while let Some(op) = codex_op_rx.recv().await {
|
||||
let id = conversation_clone.submit(op).await;
|
||||
let id = thread_clone.submit(op).await;
|
||||
if let Err(e) = id {
|
||||
tracing::error!("failed to submit op: {e}");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
while let Ok(event) = conversation.next_event().await {
|
||||
while let Ok(event) = thread.next_event().await {
|
||||
app_event_tx_clone.send(AppEvent::CodexEvent(event));
|
||||
}
|
||||
});
|
||||
@@ -70,11 +70,11 @@ pub(crate) fn spawn_agent(
|
||||
codex_op_tx
|
||||
}
|
||||
|
||||
/// Spawn agent loops for an existing conversation (e.g., a forked conversation).
|
||||
/// Spawn agent loops for an existing thread (e.g., a forked thread).
|
||||
/// Sends the provided `SessionConfiguredEvent` immediately, then forwards subsequent
|
||||
/// events and accepts Ops for submission.
|
||||
pub(crate) fn spawn_agent_from_existing(
|
||||
conversation: std::sync::Arc<CodexConversation>,
|
||||
thread: std::sync::Arc<CodexThread>,
|
||||
session_configured: codex_core::protocol::SessionConfiguredEvent,
|
||||
app_event_tx: AppEventSender,
|
||||
) -> UnboundedSender<Op> {
|
||||
@@ -89,17 +89,17 @@ pub(crate) fn spawn_agent_from_existing(
|
||||
};
|
||||
app_event_tx_clone.send(AppEvent::CodexEvent(ev));
|
||||
|
||||
let conversation_clone = conversation.clone();
|
||||
let thread_clone = thread.clone();
|
||||
tokio::spawn(async move {
|
||||
while let Some(op) = codex_op_rx.recv().await {
|
||||
let id = conversation_clone.submit(op).await;
|
||||
let id = thread_clone.submit(op).await;
|
||||
if let Err(e) = id {
|
||||
tracing::error!("failed to submit op: {e}");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
while let Ok(event) = conversation.next_event().await {
|
||||
while let Ok(event) = thread.next_event().await {
|
||||
app_event_tx_clone.send(AppEvent::CodexEvent(event));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -45,7 +45,7 @@ use codex_core::protocol::UndoCompletedEvent;
|
||||
use codex_core::protocol::UndoStartedEvent;
|
||||
use codex_core::protocol::ViewImageToolCallEvent;
|
||||
use codex_core::protocol::WarningEvent;
|
||||
use codex_protocol::ConversationId;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::account::PlanType;
|
||||
use codex_protocol::openai_models::ModelPreset;
|
||||
use codex_protocol::openai_models::ReasoningEffortPreset;
|
||||
@@ -99,7 +99,7 @@ fn snapshot(percent: f64) -> RateLimitSnapshot {
|
||||
async fn resumed_initial_messages_render_history() {
|
||||
let (mut chat, mut rx, _ops) = make_chatwidget_manual(None).await;
|
||||
|
||||
let conversation_id = ConversationId::new();
|
||||
let conversation_id = ThreadId::new();
|
||||
let rollout_file = NamedTempFile::new().unwrap();
|
||||
let configured = codex_core::protocol::SessionConfiguredEvent {
|
||||
session_id: conversation_id,
|
||||
@@ -311,7 +311,7 @@ async fn helpers_are_available_and_do_not_panic() {
|
||||
let tx = AppEventSender::new(tx_raw);
|
||||
let cfg = test_config().await;
|
||||
let resolved_model = ModelsManager::get_model_offline(cfg.model.as_deref());
|
||||
let conversation_manager = Arc::new(ConversationManager::with_models_provider(
|
||||
let thread_manager = Arc::new(ThreadManager::with_models_provider(
|
||||
CodexAuth::from_api_key("test"),
|
||||
cfg.model_provider.clone(),
|
||||
));
|
||||
@@ -324,12 +324,12 @@ async fn helpers_are_available_and_do_not_panic() {
|
||||
initial_images: Vec::new(),
|
||||
enhanced_keys_supported: false,
|
||||
auth_manager,
|
||||
models_manager: conversation_manager.get_models_manager(),
|
||||
models_manager: thread_manager.get_models_manager(),
|
||||
feedback: codex_feedback::CodexFeedback::new(),
|
||||
is_first_run: true,
|
||||
model: resolved_model,
|
||||
};
|
||||
let mut w = ChatWidget::new(init, conversation_manager);
|
||||
let mut w = ChatWidget::new(init, thread_manager);
|
||||
// Basic construction sanity.
|
||||
let _ = &mut w;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ use codex_core::config::ConfigOverrides;
|
||||
use codex_core::config::find_codex_home;
|
||||
use codex_core::config::load_config_as_toml_with_cli_overrides;
|
||||
use codex_core::config::resolve_oss_provider;
|
||||
use codex_core::find_conversation_path_by_id_str;
|
||||
use codex_core::find_thread_path_by_id_str;
|
||||
use codex_core::get_platform_sandbox;
|
||||
use codex_core::protocol::AskForApproval;
|
||||
use codex_protocol::config_types::SandboxMode;
|
||||
@@ -450,7 +450,7 @@ async fn run_ratatui_app(
|
||||
|
||||
// Determine resume behavior: explicit id, then resume last, then picker.
|
||||
let resume_selection = if let Some(id_str) = cli.resume_session_id.as_deref() {
|
||||
match find_conversation_path_by_id_str(&config.codex_home, id_str).await? {
|
||||
match find_thread_path_by_id_str(&config.codex_home, id_str).await? {
|
||||
Some(path) => resume_picker::ResumeSelection::Resume(path),
|
||||
None => {
|
||||
error!("Error finding conversation path: {id_str}");
|
||||
@@ -473,7 +473,7 @@ async fn run_ratatui_app(
|
||||
}
|
||||
} else if cli.resume_last {
|
||||
let provider_filter = vec![config.model_provider_id.clone()];
|
||||
match RolloutRecorder::list_conversations(
|
||||
match RolloutRecorder::list_threads(
|
||||
&config.codex_home,
|
||||
1,
|
||||
None,
|
||||
|
||||
@@ -5,11 +5,11 @@ use std::sync::Arc;
|
||||
|
||||
use chrono::DateTime;
|
||||
use chrono::Utc;
|
||||
use codex_core::ConversationItem;
|
||||
use codex_core::ConversationsPage;
|
||||
use codex_core::Cursor;
|
||||
use codex_core::INTERACTIVE_SESSION_SOURCES;
|
||||
use codex_core::RolloutRecorder;
|
||||
use codex_core::ThreadItem;
|
||||
use codex_core::ThreadsPage;
|
||||
use codex_core::path_utils;
|
||||
use codex_protocol::items::TurnItem;
|
||||
use color_eyre::eyre::Result;
|
||||
@@ -61,7 +61,7 @@ enum BackgroundEvent {
|
||||
PageLoaded {
|
||||
request_token: usize,
|
||||
search_token: Option<usize>,
|
||||
page: std::io::Result<ConversationsPage>,
|
||||
page: std::io::Result<ThreadsPage>,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ pub async fn run_resume_picker(
|
||||
let tx = loader_tx.clone();
|
||||
tokio::spawn(async move {
|
||||
let provider_filter = vec![request.default_provider.clone()];
|
||||
let page = RolloutRecorder::list_conversations(
|
||||
let page = RolloutRecorder::list_threads(
|
||||
&request.codex_home,
|
||||
PAGE_SIZE,
|
||||
request.cursor.as_ref(),
|
||||
@@ -415,7 +415,7 @@ impl PickerState {
|
||||
self.pagination.loading = LoadingState::Idle;
|
||||
}
|
||||
|
||||
fn ingest_page(&mut self, page: ConversationsPage) {
|
||||
fn ingest_page(&mut self, page: ThreadsPage) {
|
||||
if let Some(cursor) = page.next_cursor.clone() {
|
||||
self.pagination.next_cursor = Some(cursor);
|
||||
} else {
|
||||
@@ -627,11 +627,11 @@ impl PickerState {
|
||||
}
|
||||
}
|
||||
|
||||
fn rows_from_items(items: Vec<ConversationItem>) -> Vec<Row> {
|
||||
fn rows_from_items(items: Vec<ThreadItem>) -> Vec<Row> {
|
||||
items.into_iter().map(|item| head_to_row(&item)).collect()
|
||||
}
|
||||
|
||||
fn head_to_row(item: &ConversationItem) -> Row {
|
||||
fn head_to_row(item: &ThreadItem) -> Row {
|
||||
let created_at = item
|
||||
.created_at
|
||||
.as_deref()
|
||||
@@ -1077,8 +1077,8 @@ mod tests {
|
||||
]
|
||||
}
|
||||
|
||||
fn make_item(path: &str, ts: &str, preview: &str) -> ConversationItem {
|
||||
ConversationItem {
|
||||
fn make_item(path: &str, ts: &str, preview: &str) -> ThreadItem {
|
||||
ThreadItem {
|
||||
path: PathBuf::from(path),
|
||||
head: head_with_ts_and_user_text(ts, &[preview]),
|
||||
created_at: Some(ts.to_string()),
|
||||
@@ -1092,12 +1092,12 @@ mod tests {
|
||||
}
|
||||
|
||||
fn page(
|
||||
items: Vec<ConversationItem>,
|
||||
items: Vec<ThreadItem>,
|
||||
next_cursor: Option<Cursor>,
|
||||
num_scanned_files: usize,
|
||||
reached_scan_cap: bool,
|
||||
) -> ConversationsPage {
|
||||
ConversationsPage {
|
||||
) -> ThreadsPage {
|
||||
ThreadsPage {
|
||||
items,
|
||||
next_cursor,
|
||||
num_scanned_files,
|
||||
@@ -1144,13 +1144,13 @@ mod tests {
|
||||
#[test]
|
||||
fn rows_from_items_preserves_backend_order() {
|
||||
// Construct two items with different timestamps and real user text.
|
||||
let a = ConversationItem {
|
||||
let a = ThreadItem {
|
||||
path: PathBuf::from("/tmp/a.jsonl"),
|
||||
head: head_with_ts_and_user_text("2025-01-01T00:00:00Z", &["A"]),
|
||||
created_at: Some("2025-01-01T00:00:00Z".into()),
|
||||
updated_at: Some("2025-01-01T00:00:00Z".into()),
|
||||
};
|
||||
let b = ConversationItem {
|
||||
let b = ThreadItem {
|
||||
path: PathBuf::from("/tmp/b.jsonl"),
|
||||
head: head_with_ts_and_user_text("2025-01-02T00:00:00Z", &["B"]),
|
||||
created_at: Some("2025-01-02T00:00:00Z".into()),
|
||||
@@ -1166,7 +1166,7 @@ mod tests {
|
||||
#[test]
|
||||
fn row_uses_tail_timestamp_for_updated_at() {
|
||||
let head = head_with_ts_and_user_text("2025-01-01T00:00:00Z", &["Hello"]);
|
||||
let item = ConversationItem {
|
||||
let item = ThreadItem {
|
||||
path: PathBuf::from("/tmp/a.jsonl"),
|
||||
head,
|
||||
created_at: Some("2025-01-01T00:00:00Z".into()),
|
||||
@@ -1351,7 +1351,7 @@ mod tests {
|
||||
None,
|
||||
);
|
||||
|
||||
let page = RolloutRecorder::list_conversations(
|
||||
let page = RolloutRecorder::list_threads(
|
||||
&state.codex_home,
|
||||
PAGE_SIZE,
|
||||
None,
|
||||
|
||||
@@ -11,7 +11,7 @@ use codex_core::protocol::NetworkAccess;
|
||||
use codex_core::protocol::SandboxPolicy;
|
||||
use codex_core::protocol::TokenUsage;
|
||||
use codex_core::protocol::TokenUsageInfo;
|
||||
use codex_protocol::ConversationId;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::account::PlanType;
|
||||
use ratatui::prelude::*;
|
||||
use ratatui::style::Stylize;
|
||||
@@ -74,7 +74,7 @@ pub(crate) fn new_status_output(
|
||||
auth_manager: &AuthManager,
|
||||
token_info: Option<&TokenUsageInfo>,
|
||||
total_usage: &TokenUsage,
|
||||
session_id: &Option<ConversationId>,
|
||||
session_id: &Option<ThreadId>,
|
||||
rate_limits: Option<&RateLimitSnapshotDisplay>,
|
||||
plan_type: Option<PlanType>,
|
||||
now: DateTime<Local>,
|
||||
@@ -103,7 +103,7 @@ impl StatusHistoryCell {
|
||||
auth_manager: &AuthManager,
|
||||
token_info: Option<&TokenUsageInfo>,
|
||||
total_usage: &TokenUsage,
|
||||
session_id: &Option<ConversationId>,
|
||||
session_id: &Option<ThreadId>,
|
||||
rate_limits: Option<&RateLimitSnapshotDisplay>,
|
||||
plan_type: Option<PlanType>,
|
||||
now: DateTime<Local>,
|
||||
|
||||
Reference in New Issue
Block a user