From 4755d6fa9d8d5eb40f94ef6f99930a5eeb313892 Mon Sep 17 00:00:00 2001 From: Agus Zubiaga Date: Wed, 2 Jul 2025 13:48:57 -0300 Subject: [PATCH] Display tool icons Co-authored-by: Mikayla Maki Co-authored-by: Antonio Scandurra Co-authored-by: Nathan Sobo --- crates/acp/src/acp.rs | 59 +++++++++++++++++++++-------------- crates/acp/src/server.rs | 4 +-- crates/acp/src/thread_view.rs | 2 +- 3 files changed, 39 insertions(+), 26 deletions(-) diff --git a/crates/acp/src/acp.rs b/crates/acp/src/acp.rs index 9fbfc95f22c81510a0d777f881b29db07835eced..31d9f66dfad89a68c681eb0729d2888adfb3a5d1 100644 --- a/crates/acp/src/acp.rs +++ b/crates/acp/src/acp.rs @@ -10,7 +10,7 @@ use language::LanguageRegistry; use markdown::Markdown; use project::Project; use std::{mem, ops::Range, path::PathBuf, sync::Arc}; -use ui::App; +use ui::{App, IconName}; use util::{ResultExt, debug_panic}; pub use server::AcpServer; @@ -124,6 +124,7 @@ pub enum AgentThreadEntryContent { pub struct ToolCall { id: ToolCallId, label: Entity, + icon: IconName, status: ToolCallStatus, } @@ -272,6 +273,7 @@ impl AcpThread { pub fn request_tool_call( &mut self, label: String, + icon: acp::Icon, confirmation: acp::ToolCallConfirmation, cx: &mut Context, ) -> ToolCallRequest { @@ -282,23 +284,29 @@ impl AcpThread { respond_tx: tx, }; - let id = self.insert_tool_call(label, status, cx); + let id = self.insert_tool_call(label, status, icon, cx); ToolCallRequest { id, outcome: rx } } - pub fn push_tool_call(&mut self, label: String, cx: &mut Context) -> ToolCallId { + pub fn push_tool_call( + &mut self, + label: String, + icon: acp::Icon, + cx: &mut Context, + ) -> ToolCallId { let status = ToolCallStatus::Allowed { status: acp::ToolCallStatus::Running, content: None, }; - self.insert_tool_call(label, status, cx) + self.insert_tool_call(label, status, icon, cx) } fn insert_tool_call( &mut self, label: String, status: ToolCallStatus, + icon: acp::Icon, cx: &mut Context, ) -> ToolCallId { let language_registry = self.project.read(cx).languages().clone(); @@ -310,6 +318,7 @@ impl AcpThread { label: cx.new(|cx| { Markdown::new(label.into(), Some(language_registry.clone()), None, cx) }), + icon: acp_icon_to_ui_icon(icon), status, }), cx, @@ -433,6 +442,19 @@ impl AcpThread { } } +fn acp_icon_to_ui_icon(icon: acp::Icon) -> IconName { + match icon { + acp::Icon::FileSearch => IconName::FileSearch, + acp::Icon::Folder => IconName::Folder, + acp::Icon::Globe => IconName::Globe, + acp::Icon::Hammer => IconName::Hammer, + acp::Icon::LightBulb => IconName::LightBulb, + acp::Icon::Pencil => IconName::Pencil, + acp::Icon::Regex => IconName::Regex, + acp::Icon::Terminal => IconName::Terminal, + } +} + pub struct ToolCallRequest { pub id: ToolCallId, pub outcome: oneshot::Receiver, @@ -518,19 +540,14 @@ mod tests { }) .await .unwrap(); - thread.read_with(cx, |thread, cx| { - let AgentThreadEntryContent::ToolCall(ToolCall { - label, - status: ToolCallStatus::Allowed { .. }, - .. - }) = &thread.entries()[1].content - else { - panic!(); - }; - - label.read_with(cx, |md, _cx| { - assert_eq!(md.source(), "ReadFile"); - }); + thread.read_with(cx, |thread, _cx| { + assert!(matches!( + &thread.entries()[1].content, + AgentThreadEntryContent::ToolCall(ToolCall { + status: ToolCallStatus::Allowed { .. }, + .. + }) + )); assert!(matches!( thread.entries[2].content, @@ -558,15 +575,15 @@ mod tests { run_until_tool_call(&thread, cx).await; - let tool_call_id = thread.read_with(cx, |thread, cx| { + let tool_call_id = thread.read_with(cx, |thread, _cx| { let AgentThreadEntryContent::ToolCall(ToolCall { id, - label, status: ToolCallStatus::WaitingForConfirmation { confirmation: acp::ToolCallConfirmation::Execute { root_command, .. }, .. }, + .. }) = &thread.entries()[1].content else { panic!(); @@ -574,10 +591,6 @@ mod tests { assert_eq!(root_command, "echo"); - label.read_with(cx, |md, _cx| { - assert_eq!(md.source(), "Shell"); - }); - *id }); diff --git a/crates/acp/src/server.rs b/crates/acp/src/server.rs index 93ee4d1c137e9e24560d246ec8da898526f59cdc..e1cdbbae401deeab516d560f6ee53bc07398c71f 100644 --- a/crates/acp/src/server.rs +++ b/crates/acp/src/server.rs @@ -185,7 +185,7 @@ impl acp::Client for AcpClientDelegate { let ToolCallRequest { id, outcome } = cx .update(|cx| { self.update_thread(&request.thread_id.into(), cx, |thread, cx| { - thread.request_tool_call(request.label, request.confirmation, cx) + thread.request_tool_call(request.label, request.icon, request.confirmation, cx) }) })? .context("Failed to update thread")?; @@ -204,7 +204,7 @@ impl acp::Client for AcpClientDelegate { let entry_id = cx .update(|cx| { self.update_thread(&request.thread_id.into(), cx, |thread, cx| { - thread.push_tool_call(request.label, cx) + thread.push_tool_call(request.label, request.icon, cx) }) })? .context("Failed to update thread")?; diff --git a/crates/acp/src/thread_view.rs b/crates/acp/src/thread_view.rs index e3a9073e824407b40cdcc5ad499c11f0aedf951a..9853fd9523c5d5bdec3babfbb92be4194056160a 100644 --- a/crates/acp/src/thread_view.rs +++ b/crates/acp/src/thread_view.rs @@ -324,7 +324,7 @@ impl AcpThreadView { .w_full() .gap_1p5() .child( - Icon::new(IconName::Cog) + Icon::new(tool_call.icon.into()) .size(IconSize::Small) .color(Color::Muted), )