agent_ui: Improve UI for subagent calls (#47299)

Danilo Leal created

- Improves spacing between consecutive calls
- Only show disclosure button (i.e., ability to expand the card) when
there's actual content
- Fix font size being bigger than the actual thread
- Add gradient overlay to communicate that you can't scroll within the
card (expanding the subagent call will allow that in the near future)

Here's the result of it all, roughly:

<img width="600" height="890" alt="Screenshot 2026-01-21 at 12  26@2x"
src="https://github.com/user-attachments/assets/e5e4a544-611d-48f5-b00d-f69e869726c5"
/>

Release Notes:

- N/A

Change summary

crates/agent_ui/src/acp/thread_view.rs | 127 +++++++++++++++++----------
1 file changed, 79 insertions(+), 48 deletions(-)

Detailed changes

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

@@ -3547,21 +3547,25 @@ impl AcpThreadView {
             ToolCallStatus::Pending | ToolCallStatus::InProgress
         );
 
-        v_flex().ml_5().mr_5().my_1p5().gap_1().children(
-            subagent_threads
-                .into_iter()
-                .enumerate()
-                .map(|(context_ix, thread)| {
-                    self.render_subagent_card(
-                        entry_ix,
-                        context_ix,
-                        &thread,
-                        tool_call_in_progress,
-                        window,
-                        cx,
-                    )
-                }),
-        )
+        v_flex()
+            .mx_5()
+            .my_1p5()
+            .gap_3()
+            .children(
+                subagent_threads
+                    .into_iter()
+                    .enumerate()
+                    .map(|(context_ix, thread)| {
+                        self.render_subagent_card(
+                            entry_ix,
+                            context_ix,
+                            &thread,
+                            tool_call_in_progress,
+                            window,
+                            cx,
+                        )
+                    }),
+            )
     }
 
     fn render_subagent_card(
@@ -3600,6 +3604,17 @@ impl AcpThreadView {
                 .into_any_element()
         });
 
+        let has_expandable_content = thread_read.entries().iter().rev().any(|entry| {
+            if let AgentThreadEntry::AssistantMessage(msg) = entry {
+                msg.chunks.iter().any(|chunk| match chunk {
+                    AssistantMessageChunk::Message { block } => block.markdown().is_some(),
+                    AssistantMessageChunk::Thought { block } => block.markdown().is_some(),
+                })
+            } else {
+                false
+            }
+        });
+
         v_flex()
             .w_full()
             .rounded_md()
@@ -3645,28 +3660,30 @@ impl AcpThreadView {
                                 )
                             }),
                     )
-                    .child(
-                        Disclosure::new(
-                            SharedString::from(format!(
-                                "subagent-disclosure-inner-{}-{}",
-                                entry_ix, context_ix
-                            )),
-                            is_expanded,
-                        )
-                        .opened_icon(IconName::ChevronUp)
-                        .closed_icon(IconName::ChevronDown)
-                        .visible_on_hover(card_header_id)
-                        .on_click(cx.listener({
-                            move |this, _, _, cx| {
-                                if this.expanded_subagents.contains(&session_id) {
-                                    this.expanded_subagents.remove(&session_id);
-                                } else {
-                                    this.expanded_subagents.insert(session_id.clone());
+                    .when(has_expandable_content, |this| {
+                        this.child(
+                            Disclosure::new(
+                                SharedString::from(format!(
+                                    "subagent-disclosure-inner-{}-{}",
+                                    entry_ix, context_ix
+                                )),
+                                is_expanded,
+                            )
+                            .opened_icon(IconName::ChevronUp)
+                            .closed_icon(IconName::ChevronDown)
+                            .visible_on_hover(card_header_id)
+                            .on_click(cx.listener({
+                                move |this, _, _, cx| {
+                                    if this.expanded_subagents.contains(&session_id) {
+                                        this.expanded_subagents.remove(&session_id);
+                                    } else {
+                                        this.expanded_subagents.insert(session_id.clone());
+                                    }
+                                    cx.notify();
                                 }
-                                cx.notify();
-                            }
-                        })),
-                    ),
+                            })),
+                        )
+                    }),
             )
             .when(is_expanded, |this| {
                 this.child(
@@ -3708,25 +3725,39 @@ impl AcpThreadView {
             .clone();
 
         scroll_handle.scroll_to_bottom();
+        let editor_bg = cx.theme().colors().editor_background;
+
+        let gradient_overlay = {
+            div().absolute().inset_0().bg(linear_gradient(
+                180.,
+                linear_color_stop(editor_bg, 0.),
+                linear_color_stop(editor_bg.opacity(0.), 0.15),
+            ))
+        };
 
         div()
-            .id(format!("subagent-content-{}", session_id))
+            .relative()
             .w_full()
             .max_h_56()
-            .p_2()
+            .p_2p5()
+            .text_ui(cx)
             .border_t_1()
             .border_color(self.tool_card_border_color(cx))
-            .bg(cx.theme().colors().editor_background.opacity(0.2))
+            .bg(editor_bg.opacity(0.4))
             .overflow_hidden()
-            .track_scroll(&scroll_handle)
-            .when_some(last_assistant_markdown, |this, markdown| {
-                this.child(
-                    self.render_markdown(
-                        markdown,
-                        default_markdown_style(false, false, window, cx),
-                    ),
-                )
-            })
+            .child(
+                div()
+                    .id(format!("subagent-content-{}", session_id))
+                    .size_full()
+                    .track_scroll(&scroll_handle)
+                    .when_some(last_assistant_markdown, |this, markdown| {
+                        this.child(self.render_markdown(
+                            markdown,
+                            default_markdown_style(false, false, window, cx),
+                        ))
+                    }),
+            )
+            .child(gradient_overlay)
     }
 
     fn render_markdown_output(