diff --git a/crates/agent_ui/src/acp/thread_view.rs b/crates/agent_ui/src/acp/thread_view.rs index 14d857d1af7d4ca11915c0055f5240907b7545c7..a165577ab379e734289fe4ef59a66ba46b5dd830 100644 --- a/crates/agent_ui/src/acp/thread_view.rs +++ b/crates/agent_ui/src/acp/thread_view.rs @@ -286,6 +286,7 @@ pub struct AcpThreadView { list_state: ListState, auth_task: Option>, expanded_tool_calls: HashSet, + expanded_tool_call_raw_inputs: HashSet, expanded_thinking_blocks: HashSet<(usize, usize)>, edits_expanded: bool, plan_expanded: bool, @@ -454,6 +455,7 @@ impl AcpThreadView { thread_feedback: Default::default(), auth_task: None, expanded_tool_calls: HashSet::default(), + expanded_tool_call_raw_inputs: HashSet::default(), expanded_thinking_blocks: HashSet::default(), editing_message: None, edits_expanded: false, @@ -2730,6 +2732,9 @@ impl AcpThreadView { let is_collapsible = !tool_call.content.is_empty() && !needs_confirmation; let is_open = needs_confirmation || self.expanded_tool_calls.contains(&tool_call.id); + + let should_show_raw_input = !is_terminal_tool && !is_edit; + let input_output_header = |label: SharedString| { Label::new(label) .size(LabelSize::XSmall) @@ -2737,13 +2742,16 @@ impl AcpThreadView { .buffer_font(cx) }; - let tool_output_display = - if is_open { - match &tool_call.status { - ToolCallStatus::WaitingForConfirmation { options, .. } => v_flex() - .w_full() - .children(tool_call.content.iter().enumerate().map( - |(content_ix, content)| { + let tool_output_display = if is_open { + match &tool_call.status { + ToolCallStatus::WaitingForConfirmation { options, .. } => v_flex() + .w_full() + .children( + tool_call + .content + .iter() + .enumerate() + .map(|(content_ix, content)| { div() .child(self.render_tool_call_content( entry_ix, @@ -2755,29 +2763,90 @@ impl AcpThreadView { cx, )) .into_any_element() - }, - )) - .child(self.render_permission_buttons( - tool_call.kind, - options, - entry_ix, - tool_call.id.clone(), - cx, - )) - .into_any(), - ToolCallStatus::Pending | ToolCallStatus::InProgress - if is_edit - && tool_call.content.is_empty() - && self.as_native_connection(cx).is_some() => - { - self.render_diff_loading(cx).into_any() - } - ToolCallStatus::Pending - | ToolCallStatus::InProgress - | ToolCallStatus::Completed - | ToolCallStatus::Failed - | ToolCallStatus::Canceled => v_flex() - .when(!is_edit && !is_terminal_tool, |this| { + }), + ) + .when(should_show_raw_input, |this| { + let is_raw_input_expanded = + self.expanded_tool_call_raw_inputs.contains(&tool_call.id); + + let input_header = if is_raw_input_expanded { + "Raw Input:" + } else { + "View Raw Input" + }; + + this.child( + v_flex() + .p_2() + .gap_1() + .border_t_1() + .border_color(self.tool_card_border_color(cx)) + .child( + h_flex() + .id("disclosure_container") + .pl_0p5() + .gap_1() + .justify_between() + .rounded_xs() + .hover(|s| s.bg(cx.theme().colors().element_hover)) + .child(input_output_header(input_header.into())) + .child( + Disclosure::new( + ("raw-input-disclosure", entry_ix), + is_raw_input_expanded, + ) + .opened_icon(IconName::ChevronUp) + .closed_icon(IconName::ChevronDown), + ) + .on_click(cx.listener({ + let id = tool_call.id.clone(); + + move |this: &mut Self, _, _, cx| { + if this.expanded_tool_call_raw_inputs.contains(&id) + { + this.expanded_tool_call_raw_inputs.remove(&id); + } else { + this.expanded_tool_call_raw_inputs + .insert(id.clone()); + } + cx.notify(); + } + })), + ) + .when(is_raw_input_expanded, |this| { + this.children(tool_call.raw_input_markdown.clone().map( + |input| { + self.render_markdown( + input, + default_markdown_style(false, false, window, cx), + ) + }, + )) + }), + ) + }) + .child(self.render_permission_buttons( + tool_call.kind, + options, + entry_ix, + tool_call.id.clone(), + cx, + )) + .into_any(), + ToolCallStatus::Pending | ToolCallStatus::InProgress + if is_edit + && tool_call.content.is_empty() + && self.as_native_connection(cx).is_some() => + { + self.render_diff_loading(cx).into_any() + } + ToolCallStatus::Pending + | ToolCallStatus::InProgress + | ToolCallStatus::Completed + | ToolCallStatus::Failed + | ToolCallStatus::Canceled => { + v_flex() + .when(should_show_raw_input, |this| { this.mt_1p5().w_full().child( v_flex() .ml(rems(0.4)) @@ -2813,13 +2882,14 @@ impl AcpThreadView { ) }, )) - .into_any(), - ToolCallStatus::Rejected => Empty.into_any(), + .into_any() } - .into() - } else { - None - }; + ToolCallStatus::Rejected => Empty.into_any(), + } + .into() + } else { + None + }; v_flex() .map(|this| {