mirror of
https://github.com/openai/codex.git
synced 2026-10-24 18:18:41 +00:00
Allow review while MCPs are loading
This commit is contained in:
@@ -1810,9 +1810,6 @@ impl ChatWidget {
|
||||
{
|
||||
let op: AppCommand = op.into();
|
||||
self.prepare_local_op_submission(&op);
|
||||
if op.is_review() && !self.bottom_pane.is_task_running() {
|
||||
self.bottom_pane.set_task_running(/*running*/ true);
|
||||
}
|
||||
match &self.codex_op_target {
|
||||
CodexOpTarget::Direct(codex_op_tx) => {
|
||||
crate::session_log::log_outbound_op(&op);
|
||||
@@ -1838,6 +1835,12 @@ impl ChatWidget {
|
||||
}
|
||||
|
||||
pub(crate) fn prepare_local_op_submission(&mut self, op: &AppCommand) {
|
||||
if op.is_review() && !self.turn_lifecycle.agent_turn_running {
|
||||
self.skip_mcp_startup_for_review();
|
||||
if !self.bottom_pane.is_task_running() {
|
||||
self.bottom_pane.set_task_running(/*running*/ true);
|
||||
}
|
||||
}
|
||||
if let AppCommand::Interrupt { behavior } = op
|
||||
&& self.turn_lifecycle.agent_turn_running
|
||||
{
|
||||
|
||||
@@ -210,6 +210,23 @@ impl ChatWidget {
|
||||
self.request_redraw();
|
||||
}
|
||||
|
||||
pub(super) fn skip_mcp_startup_for_review(&mut self) {
|
||||
if self.mcp_startup_status.is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mcp_startup_owned_status = self.status_header_is_mcp_startup_owned();
|
||||
self.mcp_startup_status = None;
|
||||
self.mcp_startup_ignore_updates_until_next_start = true;
|
||||
self.mcp_startup_allow_terminal_only_next_round = false;
|
||||
self.mcp_startup_pending_next_round.clear();
|
||||
self.mcp_startup_pending_next_round_saw_starting = false;
|
||||
if mcp_startup_owned_status {
|
||||
self.set_status_header(String::from("Working"));
|
||||
}
|
||||
self.request_redraw();
|
||||
}
|
||||
|
||||
pub(crate) fn finish_mcp_startup_after_lag(&mut self) {
|
||||
if self.mcp_startup_ignore_updates_until_next_start {
|
||||
if self.mcp_startup_pending_next_round.is_empty() {
|
||||
|
||||
@@ -132,6 +132,13 @@ impl ChatWidget {
|
||||
}
|
||||
|
||||
fn slash_command_blocked_by_active_task(&self, cmd: SlashCommand) -> bool {
|
||||
if cmd == SlashCommand::Review {
|
||||
let mcp_startup_is_only_task = self.mcp_startup_status.is_some()
|
||||
&& !self.turn_lifecycle.agent_turn_running
|
||||
&& !self.input_queue.user_turn_pending_start
|
||||
&& !self.review.is_review_mode;
|
||||
return self.bottom_pane.is_task_running() && !mcp_startup_is_only_task;
|
||||
}
|
||||
(!cmd.available_during_task() && self.bottom_pane.is_task_running())
|
||||
|| (cmd == SlashCommand::Resume
|
||||
&& (self.input_queue.user_turn_pending_start
|
||||
|
||||
@@ -69,6 +69,53 @@ async fn mcp_startup_ignores_status_for_other_thread() {
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn review_command_during_mcp_startup_opens_popup_snapshot() {
|
||||
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await;
|
||||
notify_mcp_status(&mut chat, "alpha", McpServerStartupState::Starting);
|
||||
|
||||
chat.dispatch_command(SlashCommand::Review);
|
||||
|
||||
let popup = render_bottom_popup(&chat, /*width*/ 80);
|
||||
assert_chatwidget_snapshot!("review_command_during_mcp_startup_opens_popup", popup);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn review_with_args_during_mcp_startup_skips_local_startup_round() {
|
||||
let (mut chat, _rx, mut op_rx) = make_chatwidget_manual(/*model_override*/ None).await;
|
||||
notify_mcp_status(&mut chat, "alpha", McpServerStartupState::Starting);
|
||||
|
||||
chat.dispatch_command_with_args(
|
||||
SlashCommand::Review,
|
||||
"check regressions".to_string(),
|
||||
Vec::new(),
|
||||
);
|
||||
|
||||
assert_matches!(
|
||||
op_rx.try_recv(),
|
||||
Ok(Op::Review {
|
||||
target: ReviewTarget::Custom { instructions }
|
||||
}) if instructions == "check regressions"
|
||||
);
|
||||
assert!(chat.mcp_startup_status.is_none());
|
||||
assert!(chat.bottom_pane.is_task_running());
|
||||
assert_eq!(chat.status_state.current_status.header, "Working");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn review_command_remains_blocked_during_agent_turn() {
|
||||
let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await;
|
||||
handle_turn_started(&mut chat, "turn-1");
|
||||
|
||||
chat.dispatch_command(SlashCommand::Review);
|
||||
|
||||
let error = drain_insert_history(&mut rx)
|
||||
.into_iter()
|
||||
.map(|lines| lines_to_single_string(&lines))
|
||||
.collect::<String>();
|
||||
assert!(error.contains("'/review' is disabled while a task is in progress."));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn mcp_startup_dedupes_same_round_duplicate_failure_warning() {
|
||||
let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await;
|
||||
|
||||
@@ -200,7 +200,6 @@ impl SlashCommand {
|
||||
| SlashCommand::Experimental
|
||||
| SlashCommand::Memories
|
||||
| SlashCommand::Import
|
||||
| SlashCommand::Review
|
||||
| SlashCommand::Plan
|
||||
| SlashCommand::Clear
|
||||
| SlashCommand::Logout
|
||||
@@ -208,6 +207,7 @@ impl SlashCommand {
|
||||
| SlashCommand::MemoryUpdate => false,
|
||||
SlashCommand::Diff
|
||||
| SlashCommand::Resume
|
||||
| SlashCommand::Review
|
||||
| SlashCommand::Model
|
||||
| SlashCommand::Personality
|
||||
| SlashCommand::Permissions
|
||||
@@ -295,6 +295,7 @@ mod tests {
|
||||
assert!(SlashCommand::Raw.available_in_side_conversation());
|
||||
assert!(SlashCommand::Raw.supports_inline_args());
|
||||
assert!(SlashCommand::App.available_during_task());
|
||||
assert!(SlashCommand::Review.available_during_task());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user