From 358cb1c62043c0e2dcbc176902a3082fc7249e0f Mon Sep 17 00:00:00 2001 From: Oz Date: Tue, 30 Jun 2026 19:53:52 +0000 Subject: [PATCH] Fix misleading 'orchestration disabled' copy on denied run_agents card MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The run_agents confirmation card rendered every RunAgentsResult::Denied outcome as "Orchestration is currently disabled. Re-enable on the plan card to launch." — regardless of the actual denial reason. The most common denial is the duplicate-launch guard (the agent re-ran run_agents for child agents that were already spawned), which leaves orchestration fully enabled. That false banner led users to believe orchestration had been turned off per-conversation and that their already-launched subagents had been cancelled, and pointed them at a re-enable affordance the terminal card does not have. format_terminal_state now surfaces the actual denial reason, and renders the empty-reason 'Accept w/o orchestration' choice as a deliberate skip. Co-Authored-By: Warp --- .../inline_action/run_agents_card_view.rs | 18 +++++++---- .../run_agents_card_view_tests.rs | 30 +++++++++++++++---- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/app/src/ai/blocklist/inline_action/run_agents_card_view.rs b/app/src/ai/blocklist/inline_action/run_agents_card_view.rs index de74275fc9..95ca17a1b6 100644 --- a/app/src/ai/blocklist/inline_action/run_agents_card_view.rs +++ b/app/src/ai/blocklist/inline_action/run_agents_card_view.rs @@ -1391,13 +1391,19 @@ pub(crate) fn format_terminal_state(result: &RunAgentsResult) -> (String, Status } } RunAgentsResult::Denied { reason } => { - let body = if reason.is_empty() { - "Orchestration is currently disabled. Re-enable on the plan card to launch." - .to_string() + // A denial is not the same as orchestration being disabled. The + // request can be declined while orchestration is fully enabled — + // most commonly by the duplicate-launch guard (the agent re-ran + // run_agents for children that were already spawned). Surface the + // actual reason instead of always claiming orchestration is off, + // which previously misled users whose agents were merely duplicates + // and pointed them at a "plan card" re-enable affordance that the + // terminal card doesn't have. + let body = if reason.trim().is_empty() { + // An empty reason is the user's "Accept w/o orchestration" choice. + "Continued without orchestration.".to_string() } else { - format!( - "Orchestration is currently disabled. Re-enable on the plan card to launch. ({reason})" - ) + reason.clone() }; (body, StatusKind::Cancelled) } diff --git a/app/src/ai/blocklist/inline_action/run_agents_card_view_tests.rs b/app/src/ai/blocklist/inline_action/run_agents_card_view_tests.rs index 54fd30d482..e24a25758f 100644 --- a/app/src/ai/blocklist/inline_action/run_agents_card_view_tests.rs +++ b/app/src/ai/blocklist/inline_action/run_agents_card_view_tests.rs @@ -347,20 +347,40 @@ mod format_terminal_state_tests { } #[test] - fn denied_with_reason_appends_reason() { + fn denied_with_reason_surfaces_reason() { let (label, kind) = format_terminal_state(&RunAgentsResult::Denied { - reason: "disapproved".to_string(), + reason: "Orchestration config was disapproved".to_string(), }); - assert!(label.contains("disapproved")); + assert_eq!(label, "Orchestration config was disapproved"); + // A denial must not falsely claim orchestration is disabled. + assert!(!label.contains("Orchestration is currently disabled")); assert!(matches!(kind, StatusKind::Cancelled)); } #[test] - fn denied_without_reason_uses_short_label() { + fn denied_with_duplicate_launch_reason_does_not_claim_disabled() { + // Regression: the duplicate-launch guard denies a run_agents call while + // orchestration is fully enabled (the agent re-ran run_agents for + // children that were already spawned). The card must surface that + // reason, not the misleading "Orchestration is currently disabled" copy. + let reason = "Requested agent(s) have already been launched: frontend (a-1). \ + Do not start duplicate child agents; send any follow-up with \ + send_message_to_agent using the existing agent id(s): a-1."; + let (label, kind) = format_terminal_state(&RunAgentsResult::Denied { + reason: reason.to_string(), + }); + assert_eq!(label, reason); + assert!(!label.contains("Orchestration is currently disabled")); + assert!(matches!(kind, StatusKind::Cancelled)); + } + + #[test] + fn denied_without_reason_reads_as_deliberate_skip() { let (label, kind) = format_terminal_state(&RunAgentsResult::Denied { reason: String::new(), }); - assert!(!label.contains("()")); + assert_eq!(label, "Continued without orchestration."); + assert!(!label.contains("Orchestration is currently disabled")); assert!(matches!(kind, StatusKind::Cancelled)); }