mirror of
https://github.com/openai/codex.git
synced 2026-10-30 19:18:49 +00:00
tui: serialize exact resume picker targets
Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
co-authored by
Codex
parent
7bcff58ea4
commit
295f7fe976
@@ -2523,7 +2523,9 @@ impl App {
|
||||
AppEvent::OpenResumePicker => {
|
||||
match crate::resume_picker::run_resume_picker(tui, &self.config, false).await? {
|
||||
SessionSelection::Resume(target_session) => {
|
||||
self.chat_widget.handle_resume_selection(target_session);
|
||||
self.chat_widget.handle_serialized_slash_command(
|
||||
ChatWidget::resume_selection_draft(&target_session),
|
||||
);
|
||||
self.refresh_status_line();
|
||||
}
|
||||
SessionSelection::Exit
|
||||
|
||||
@@ -268,7 +268,6 @@ use crate::render::renderable::FlexRenderable;
|
||||
use crate::render::renderable::Renderable;
|
||||
use crate::render::renderable::RenderableExt;
|
||||
use crate::render::renderable::RenderableItem;
|
||||
use crate::resume_picker::SessionTarget;
|
||||
use crate::slash_command::SlashCommand;
|
||||
use crate::status::RateLimitSnapshotDisplay;
|
||||
use crate::status_indicator_widget::STATUS_DETAILS_DEFAULT_MAX_LINES;
|
||||
@@ -736,11 +735,6 @@ pub(crate) struct ChatWidget {
|
||||
// drafts and are replayed through the slash-command evaluator instead of being submitted
|
||||
// directly as user turns.
|
||||
queued_user_messages: VecDeque<UserMessage>,
|
||||
// Exact rollout targets picked from the resume picker for queued `/resume <thread-id>` drafts.
|
||||
//
|
||||
// The serialized draft stays human-readable, but replay consumes these targets in queue order
|
||||
// so the selected rollout path is preserved instead of being re-resolved by thread id later.
|
||||
queued_resume_targets: VecDeque<SessionTarget>,
|
||||
// Steers already submitted to core but not yet committed into history.
|
||||
//
|
||||
// The bottom pane shows these above queued drafts until core records the
|
||||
@@ -899,7 +893,6 @@ pub(crate) struct ThreadInputState {
|
||||
composer: Option<ThreadComposerState>,
|
||||
pending_steers: VecDeque<UserMessage>,
|
||||
queued_user_messages: VecDeque<UserMessage>,
|
||||
queued_resume_targets: VecDeque<SessionTarget>,
|
||||
current_collaboration_mode: CollaborationMode,
|
||||
active_collaboration_mask: Option<CollaborationModeMask>,
|
||||
agent_turn_running: bool,
|
||||
@@ -2275,7 +2268,6 @@ impl ChatWidget {
|
||||
.map(|steer| steer.user_message)
|
||||
.collect();
|
||||
to_merge.extend(self.queued_user_messages.drain(..));
|
||||
self.queued_resume_targets.clear();
|
||||
if has_existing_message {
|
||||
to_merge.push(existing_message);
|
||||
}
|
||||
@@ -2318,7 +2310,6 @@ impl ChatWidget {
|
||||
.map(|pending| pending.user_message.clone())
|
||||
.collect(),
|
||||
queued_user_messages: self.queued_user_messages.clone(),
|
||||
queued_resume_targets: self.queued_resume_targets.clone(),
|
||||
current_collaboration_mode: self.current_collaboration_mode.clone(),
|
||||
active_collaboration_mask: self.active_collaboration_mask.clone(),
|
||||
agent_turn_running: self.agent_turn_running,
|
||||
@@ -2361,7 +2352,6 @@ impl ChatWidget {
|
||||
self.queued_user_messages = input_state.pending_steers;
|
||||
self.queued_user_messages
|
||||
.extend(input_state.queued_user_messages);
|
||||
self.queued_resume_targets = input_state.queued_resume_targets;
|
||||
} else {
|
||||
self.agent_turn_running = false;
|
||||
self.pending_steers.clear();
|
||||
@@ -2374,7 +2364,6 @@ impl ChatWidget {
|
||||
);
|
||||
self.bottom_pane.set_composer_pending_pastes(Vec::new());
|
||||
self.queued_user_messages.clear();
|
||||
self.queued_resume_targets.clear();
|
||||
}
|
||||
self.turn_sleep_inhibitor
|
||||
.set_turn_running(self.agent_turn_running);
|
||||
@@ -3656,7 +3645,6 @@ impl ChatWidget {
|
||||
thread_name: None,
|
||||
forked_from: None,
|
||||
queued_user_messages: VecDeque::new(),
|
||||
queued_resume_targets: VecDeque::new(),
|
||||
pending_steers: VecDeque::new(),
|
||||
submit_pending_steers_after_interrupt: false,
|
||||
queued_message_edit_binding,
|
||||
@@ -3848,7 +3836,6 @@ impl ChatWidget {
|
||||
plan_delta_buffer: String::new(),
|
||||
plan_item_active: false,
|
||||
queued_user_messages: VecDeque::new(),
|
||||
queued_resume_targets: VecDeque::new(),
|
||||
pending_steers: VecDeque::new(),
|
||||
submit_pending_steers_after_interrupt: false,
|
||||
queued_message_edit_binding,
|
||||
@@ -4024,7 +4011,6 @@ impl ChatWidget {
|
||||
thread_name: None,
|
||||
forked_from: None,
|
||||
queued_user_messages: VecDeque::new(),
|
||||
queued_resume_targets: VecDeque::new(),
|
||||
pending_steers: VecDeque::new(),
|
||||
submit_pending_steers_after_interrupt: false,
|
||||
queued_message_edit_binding,
|
||||
@@ -4159,12 +4145,6 @@ impl ChatWidget {
|
||||
&& !self.queued_user_messages.is_empty()
|
||||
{
|
||||
if let Some(queued_message) = self.queued_user_messages.pop_back() {
|
||||
if self
|
||||
.parse_builtin_slash_command(&queued_message.text)
|
||||
.is_some_and(|(cmd, _, _)| cmd == SlashCommand::Resume)
|
||||
{
|
||||
self.queued_resume_targets.pop_back();
|
||||
}
|
||||
self.restore_user_message_to_composer(queued_message);
|
||||
self.refresh_pending_input_preview();
|
||||
self.request_redraw();
|
||||
@@ -5324,7 +5304,7 @@ impl ChatWidget {
|
||||
SlashCommand::Resume => {
|
||||
let args = match SlashCommandInvocation::parse_args(
|
||||
&args_message.text,
|
||||
"Usage: /resume <thread-id>",
|
||||
"Usage: /resume <thread-id> [--path <rollout-path>]",
|
||||
) {
|
||||
Ok(args) => args,
|
||||
Err(message) => {
|
||||
@@ -5335,26 +5315,22 @@ impl ChatWidget {
|
||||
);
|
||||
}
|
||||
};
|
||||
if args.len() != 1 {
|
||||
if !(args.len() == 1 || (args.len() == 3 && args[1] == "--path")) {
|
||||
return self.restore_invalid_inline_slash_command(
|
||||
cmd,
|
||||
args_message,
|
||||
"Usage: /resume <thread-id>".to_string(),
|
||||
"Usage: /resume <thread-id> [--path <rollout-path>]".to_string(),
|
||||
);
|
||||
}
|
||||
match ThreadId::from_string(&args[0]) {
|
||||
Ok(thread_id) => {
|
||||
if self
|
||||
.queued_resume_targets
|
||||
.front()
|
||||
.is_some_and(|target| target.thread_id == thread_id)
|
||||
{
|
||||
if let Some(target_session) = self.queued_resume_targets.pop_front() {
|
||||
self.app_event_tx
|
||||
.send(AppEvent::ResumeSessionTarget(target_session));
|
||||
} else {
|
||||
self.app_event_tx.send(AppEvent::ResumeSession(thread_id));
|
||||
}
|
||||
if let Some(path) = args.get(2) {
|
||||
self.app_event_tx.send(AppEvent::ResumeSessionTarget(
|
||||
crate::resume_picker::SessionTarget {
|
||||
path: PathBuf::from(path),
|
||||
thread_id,
|
||||
},
|
||||
));
|
||||
} else {
|
||||
self.app_event_tx.send(AppEvent::ResumeSession(thread_id));
|
||||
}
|
||||
@@ -5363,7 +5339,7 @@ impl ChatWidget {
|
||||
Err(_) => self.restore_invalid_inline_slash_command(
|
||||
cmd,
|
||||
args_message,
|
||||
"Usage: /resume <thread-id>".to_string(),
|
||||
"Usage: /resume <thread-id> [--path <rollout-path>]".to_string(),
|
||||
),
|
||||
}
|
||||
}
|
||||
@@ -5729,6 +5705,20 @@ impl ChatWidget {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn resume_selection_draft(
|
||||
target_session: &crate::resume_picker::SessionTarget,
|
||||
) -> UserMessage {
|
||||
SlashCommandInvocation::with_args(
|
||||
SlashCommand::Resume,
|
||||
[
|
||||
target_session.thread_id.to_string(),
|
||||
"--path".to_string(),
|
||||
target_session.path.display().to_string(),
|
||||
],
|
||||
)
|
||||
.into_user_message()
|
||||
}
|
||||
|
||||
pub(crate) fn handle_serialized_slash_command(&mut self, draft: UserMessage) {
|
||||
let Some((cmd, _, _)) = self.parse_builtin_slash_command(&draft.text) else {
|
||||
if self.reject_unavailable_builtin_slash_command(&draft) {
|
||||
@@ -5745,17 +5735,6 @@ impl ChatWidget {
|
||||
let _ = self.execute_serialized_slash_command(draft);
|
||||
}
|
||||
|
||||
pub(crate) fn handle_resume_selection(&mut self, target_session: SessionTarget) {
|
||||
self.queued_resume_targets.push_back(target_session.clone());
|
||||
self.handle_serialized_slash_command(
|
||||
SlashCommandInvocation::with_args(
|
||||
SlashCommand::Resume,
|
||||
[target_session.thread_id.to_string()],
|
||||
)
|
||||
.into_user_message(),
|
||||
);
|
||||
}
|
||||
|
||||
fn submit_plan_user_message(&mut self, user_message: UserMessage) {
|
||||
if self.is_session_configured() {
|
||||
self.reasoning_buffer.clear();
|
||||
|
||||
+2
-1
@@ -83,6 +83,7 @@ expression: popup
|
||||
Usage:
|
||||
/resume
|
||||
/resume <thread-id>
|
||||
/resume <thread-id> --path <rollout-path>
|
||||
|
||||
/fork
|
||||
fork the current chat
|
||||
@@ -240,4 +241,4 @@ expression: popup
|
||||
/debug-m-drop
|
||||
|
||||
|
||||
↑/↓ scroll | [ctrl + p / ctrl + n] page | / search | esc close 1-232/239
|
||||
↑/↓ scroll | [ctrl + p / ctrl + n] page | / search | esc close 1-233/240
|
||||
|
||||
+1
@@ -88,6 +88,7 @@ expression: popup
|
||||
Usage:
|
||||
/resume
|
||||
/resume <thread-id>
|
||||
/resume <thread-id> --path <rollout-path>
|
||||
|
||||
/fork
|
||||
fork the current chat
|
||||
|
||||
+2
-1
@@ -83,6 +83,7 @@ expression: searching
|
||||
Usage:
|
||||
/resume
|
||||
/resume <thread-id>
|
||||
/resume <thread-id> --path <rollout-path>
|
||||
|
||||
/fork
|
||||
fork the current chat
|
||||
@@ -240,4 +241,4 @@ expression: searching
|
||||
/debug-m-drop
|
||||
|
||||
|
||||
Search: /maintainers | enter apply | esc cancel 1 match | 1-232/239
|
||||
Search: /maintainers | enter apply | esc cancel 1 match | 1-233/240
|
||||
|
||||
+1
@@ -88,6 +88,7 @@ expression: searching
|
||||
Usage:
|
||||
/resume
|
||||
/resume <thread-id>
|
||||
/resume <thread-id> --path <rollout-path>
|
||||
|
||||
/fork
|
||||
fork the current chat
|
||||
|
||||
@@ -1902,7 +1902,6 @@ async fn make_chatwidget_manual(
|
||||
show_welcome_banner: true,
|
||||
startup_tooltip_override: None,
|
||||
queued_user_messages: VecDeque::new(),
|
||||
queued_resume_targets: VecDeque::new(),
|
||||
pending_steers: VecDeque::new(),
|
||||
submit_pending_steers_after_interrupt: false,
|
||||
queued_message_edit_binding: crate::key_hint::alt(KeyCode::Up),
|
||||
@@ -3682,7 +3681,6 @@ async fn restore_thread_input_state_syncs_sleep_inhibitor_state() {
|
||||
composer: None,
|
||||
pending_steers: VecDeque::new(),
|
||||
queued_user_messages: VecDeque::new(),
|
||||
queued_resume_targets: VecDeque::new(),
|
||||
current_collaboration_mode: chat.current_collaboration_mode.clone(),
|
||||
active_collaboration_mask: chat.active_collaboration_mask.clone(),
|
||||
agent_turn_running: true,
|
||||
@@ -5727,8 +5725,8 @@ async fn queued_resume_picker_selection_replays_exact_targets_in_order() {
|
||||
thread_id,
|
||||
};
|
||||
|
||||
chat.handle_resume_selection(first.clone());
|
||||
chat.handle_resume_selection(second.clone());
|
||||
chat.handle_serialized_slash_command(ChatWidget::resume_selection_draft(&first));
|
||||
chat.handle_serialized_slash_command(ChatWidget::resume_selection_draft(&second));
|
||||
|
||||
chat.bottom_pane.set_task_running(false);
|
||||
chat.drain_queued_inputs_until_blocked();
|
||||
|
||||
@@ -150,7 +150,7 @@ impl SlashCommand {
|
||||
],
|
||||
SlashCommand::Rename => &["", "<title...>"],
|
||||
SlashCommand::New => &[""],
|
||||
SlashCommand::Resume => &["", "<thread-id>"],
|
||||
SlashCommand::Resume => &["", "<thread-id>", "<thread-id> --path <rollout-path>"],
|
||||
SlashCommand::Fork => &[""],
|
||||
SlashCommand::Init => &[""],
|
||||
SlashCommand::Compact => &[""],
|
||||
|
||||
Reference in New Issue
Block a user