Show red X icon for interrupted subagents (#47499)

Richard Feldman created

<img width="677" height="218" alt="Screenshot 2026-01-23 at 11 59 24 AM"
src="https://github.com/user-attachments/assets/864c706f-6f9f-44dd-a18c-509f2bed164f"
/>


When a thread is interrupted while subagents are running, the subagent
cards now show a red X icon instead of a green checkmark. This provides
clearer visual feedback that the subagent was canceled rather than
completed successfully.

The icon logic now handles three states:
- **Spinner**: when status is Pending or InProgress
- **Red X**: when status is Canceled, Failed, or Rejected  
- **Green checkmark**: when status is Completed

This matches the existing pattern used elsewhere in the codebase for
showing error states on tool calls.

(No release notes because subagents are still behind a feature flag.)

Release Notes:

- N/A

Change summary

crates/agent_ui/src/acp/thread_view.rs | 23 ++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)

Detailed changes

crates/agent_ui/src/acp/thread_view.rs 🔗

@@ -3688,10 +3688,7 @@ impl AcpThreadView {
             .filter_map(|c| c.subagent_thread().cloned())
             .collect();
 
-        let tool_call_in_progress = matches!(
-            tool_call.status,
-            ToolCallStatus::Pending | ToolCallStatus::InProgress
-        );
+        let tool_call_status = &tool_call.status;
 
         v_flex()
             .mx_5()
@@ -3706,7 +3703,7 @@ impl AcpThreadView {
                             entry_ix,
                             context_ix,
                             &thread,
-                            tool_call_in_progress,
+                            tool_call_status,
                             window,
                             cx,
                         )
@@ -3719,7 +3716,7 @@ impl AcpThreadView {
         entry_ix: usize,
         context_ix: usize,
         thread: &Entity<AcpThread>,
-        tool_call_in_progress: bool,
+        tool_call_status: &ToolCallStatus,
         window: &Window,
         cx: &Context<Self>,
     ) -> AnyElement {
@@ -3733,7 +3730,14 @@ impl AcpThreadView {
         let files_changed = changed_buffers.len();
         let diff_stats = DiffStats::all_files(&changed_buffers, cx);
 
-        let is_running = tool_call_in_progress;
+        let is_running = matches!(
+            tool_call_status,
+            ToolCallStatus::Pending | ToolCallStatus::InProgress
+        );
+        let is_canceled_or_failed = matches!(
+            tool_call_status,
+            ToolCallStatus::Canceled | ToolCallStatus::Failed | ToolCallStatus::Rejected
+        );
 
         let card_header_id =
             SharedString::from(format!("subagent-header-{}-{}", entry_ix, context_ix));
@@ -3743,6 +3747,11 @@ impl AcpThreadView {
             SpinnerLabel::new()
                 .size(LabelSize::Small)
                 .into_any_element()
+        } else if is_canceled_or_failed {
+            Icon::new(IconName::Close)
+                .size(IconSize::Small)
+                .color(Color::Error)
+                .into_any_element()
         } else {
             Icon::new(IconName::Check)
                 .size(IconSize::Small)