From 46e86f003f3afbecd15f86b598a3c3bc72483d07 Mon Sep 17 00:00:00 2001 From: Agus Zubiaga Date: Tue, 25 Mar 2025 15:17:36 -0300 Subject: [PATCH] assistant tools: Add `Tool::icon` method instead of matching on name (#27444) Release Notes: - N/A --- Cargo.lock | 2 ++ crates/assistant2/src/active_thread.rs | 19 +------------------ crates/assistant2/src/tool_use.rs | 9 +++++++++ crates/assistant_tool/Cargo.toml | 1 + crates/assistant_tool/src/assistant_tool.rs | 4 ++++ crates/assistant_tools/src/bash_tool.rs | 5 +++++ crates/assistant_tools/src/copy_path_tool.rs | 5 +++++ .../assistant_tools/src/create_file_tool.rs | 5 +++++ .../assistant_tools/src/delete_path_tool.rs | 5 +++++ .../assistant_tools/src/diagnostics_tool.rs | 5 +++++ crates/assistant_tools/src/edit_files_tool.rs | 5 +++++ crates/assistant_tools/src/fetch_tool.rs | 5 +++++ .../src/find_replace_file_tool.rs | 5 +++++ .../src/list_directory_tool.rs | 5 +++++ crates/assistant_tools/src/move_path_tool.rs | 5 +++++ crates/assistant_tools/src/now_tool.rs | 5 +++++ .../assistant_tools/src/path_search_tool.rs | 5 +++++ crates/assistant_tools/src/read_file_tool.rs | 5 +++++ .../assistant_tools/src/regex_search_tool.rs | 5 +++++ crates/assistant_tools/src/thinking_tool.rs | 5 +++++ crates/context_server/Cargo.toml | 1 + .../context_server/src/context_server_tool.rs | 5 +++++ 22 files changed, 98 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 607e0f4976..8e693f8587 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -704,6 +704,7 @@ dependencies = [ "project", "serde", "serde_json", + "ui", ] [[package]] @@ -3206,6 +3207,7 @@ dependencies = [ "serde_json", "settings", "smol", + "ui", "url", "util", ] diff --git a/crates/assistant2/src/active_thread.rs b/crates/assistant2/src/active_thread.rs index 8da640f9f4..cd6a4f342c 100644 --- a/crates/assistant2/src/active_thread.rs +++ b/crates/assistant2/src/active_thread.rs @@ -1251,23 +1251,6 @@ impl ActiveThread { let lighter_border = cx.theme().colors().border.opacity(0.5); - let tool_icon = match tool_use.name.as_ref() { - "bash" => IconName::Terminal, - "copy-path" => IconName::Clipboard, - "delete-path" => IconName::Trash, - "diagnostics" => IconName::Warning, - "edit-files" | "find-replace-file" => IconName::Pencil, - "fetch" => IconName::Globe, - "list-directory" => IconName::Folder, - "move-path" => IconName::ArrowRightLeft, - "now" => IconName::Info, - "path-search" => IconName::SearchCode, - "read-file" => IconName::Eye, - "regex-search" => IconName::Regex, - "thinking" => IconName::Brain, - _ => IconName::Cog, - }; - div().py_2().child( v_flex() .rounded_lg() @@ -1293,7 +1276,7 @@ impl ActiveThread { h_flex() .gap_1p5() .child( - Icon::new(tool_icon) + Icon::new(tool_use.icon) .size(IconSize::XSmall) .color(Color::Muted), ) diff --git a/crates/assistant2/src/tool_use.rs b/crates/assistant2/src/tool_use.rs index 9a5cfcef67..d13c711d85 100644 --- a/crates/assistant2/src/tool_use.rs +++ b/crates/assistant2/src/tool_use.rs @@ -10,6 +10,7 @@ use language_model::{ LanguageModelRequestMessage, LanguageModelToolResult, LanguageModelToolUse, LanguageModelToolUseId, MessageContent, Role, }; +use ui::IconName; use crate::thread::MessageId; use crate::thread_store::SerializedMessage; @@ -21,6 +22,7 @@ pub struct ToolUse { pub ui_text: SharedString, pub status: ToolUseStatus, pub input: serde_json::Value, + pub icon: ui::IconName, } #[derive(Debug, Clone)] @@ -179,12 +181,19 @@ impl ToolUseState { } })(); + let icon = if let Some(tool) = self.tools.tool(&tool_use.name, cx) { + tool.icon() + } else { + IconName::Cog + }; + tool_uses.push(ToolUse { id: tool_use.id.clone(), name: tool_use.name.clone().into(), ui_text: self.tool_ui_label(&tool_use.name, &tool_use.input, cx), input: tool_use.input.clone(), status, + icon, }) } diff --git a/crates/assistant_tool/Cargo.toml b/crates/assistant_tool/Cargo.toml index 040a906bf3..a34cd95dfd 100644 --- a/crates/assistant_tool/Cargo.toml +++ b/crates/assistant_tool/Cargo.toml @@ -23,3 +23,4 @@ parking_lot.workspace = true project.workspace = true serde.workspace = true serde_json.workspace = true +ui.workspace = true diff --git a/crates/assistant_tool/src/assistant_tool.rs b/crates/assistant_tool/src/assistant_tool.rs index 20fdb05439..2684e62211 100644 --- a/crates/assistant_tool/src/assistant_tool.rs +++ b/crates/assistant_tool/src/assistant_tool.rs @@ -9,6 +9,7 @@ use language_model::LanguageModelRequestMessage; use project::Project; use std::fmt::{self, Debug, Formatter}; use std::sync::Arc; +use ui::IconName; pub use crate::tool_registry::*; pub use crate::tool_working_set::*; @@ -33,6 +34,9 @@ pub trait Tool: 'static + Send + Sync { /// Returns the description of the tool. fn description(&self) -> String; + /// Returns the icon for the tool. + fn icon(&self) -> IconName; + /// Returns the source of the tool. fn source(&self) -> ToolSource { ToolSource::Native diff --git a/crates/assistant_tools/src/bash_tool.rs b/crates/assistant_tools/src/bash_tool.rs index 27a021ee12..19cf5c198c 100644 --- a/crates/assistant_tools/src/bash_tool.rs +++ b/crates/assistant_tools/src/bash_tool.rs @@ -6,6 +6,7 @@ use project::Project; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::sync::Arc; +use ui::IconName; use util::command::new_smol_command; #[derive(Debug, Serialize, Deserialize, JsonSchema)] @@ -31,6 +32,10 @@ impl Tool for BashTool { include_str!("./bash_tool/description.md").to_string() } + fn icon(&self) -> IconName { + IconName::Terminal + } + fn input_schema(&self) -> serde_json::Value { let schema = schemars::schema_for!(BashToolInput); serde_json::to_value(&schema).unwrap() diff --git a/crates/assistant_tools/src/copy_path_tool.rs b/crates/assistant_tools/src/copy_path_tool.rs index e0f325102e..d4cb85421b 100644 --- a/crates/assistant_tools/src/copy_path_tool.rs +++ b/crates/assistant_tools/src/copy_path_tool.rs @@ -6,6 +6,7 @@ use project::Project; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::sync::Arc; +use ui::IconName; #[derive(Debug, Serialize, Deserialize, JsonSchema)] pub struct CopyPathToolInput { @@ -47,6 +48,10 @@ impl Tool for CopyPathTool { include_str!("./copy_path_tool/description.md").into() } + fn icon(&self) -> IconName { + IconName::Clipboard + } + fn input_schema(&self) -> serde_json::Value { let schema = schemars::schema_for!(CopyPathToolInput); serde_json::to_value(&schema).unwrap() diff --git a/crates/assistant_tools/src/create_file_tool.rs b/crates/assistant_tools/src/create_file_tool.rs index d34db2f1c2..dc1b5c0f03 100644 --- a/crates/assistant_tools/src/create_file_tool.rs +++ b/crates/assistant_tools/src/create_file_tool.rs @@ -6,6 +6,7 @@ use project::Project; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::sync::Arc; +use ui::IconName; #[derive(Debug, Serialize, Deserialize, JsonSchema)] pub struct CreateFileToolInput { @@ -44,6 +45,10 @@ impl Tool for CreateFileTool { include_str!("./create_file_tool/description.md").into() } + fn icon(&self) -> IconName { + IconName::File + } + fn input_schema(&self) -> serde_json::Value { let schema = schemars::schema_for!(CreateFileToolInput); serde_json::to_value(&schema).unwrap() diff --git a/crates/assistant_tools/src/delete_path_tool.rs b/crates/assistant_tools/src/delete_path_tool.rs index cc13d34e80..3bd55e6c3a 100644 --- a/crates/assistant_tools/src/delete_path_tool.rs +++ b/crates/assistant_tools/src/delete_path_tool.rs @@ -6,6 +6,7 @@ use project::Project; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::sync::Arc; +use ui::IconName; #[derive(Debug, Serialize, Deserialize, JsonSchema)] pub struct DeletePathToolInput { @@ -38,6 +39,10 @@ impl Tool for DeletePathTool { include_str!("./delete_path_tool/description.md").into() } + fn icon(&self) -> IconName { + IconName::Trash + } + fn input_schema(&self) -> serde_json::Value { let schema = schemars::schema_for!(DeletePathToolInput); serde_json::to_value(&schema).unwrap() diff --git a/crates/assistant_tools/src/diagnostics_tool.rs b/crates/assistant_tools/src/diagnostics_tool.rs index 95aec472a5..a3638a431f 100644 --- a/crates/assistant_tools/src/diagnostics_tool.rs +++ b/crates/assistant_tools/src/diagnostics_tool.rs @@ -11,6 +11,7 @@ use std::{ path::{Path, PathBuf}, sync::Arc, }; +use ui::IconName; #[derive(Debug, Serialize, Deserialize, JsonSchema)] pub struct DiagnosticsToolInput { @@ -45,6 +46,10 @@ impl Tool for DiagnosticsTool { include_str!("./diagnostics_tool/description.md").into() } + fn icon(&self) -> IconName { + IconName::Warning + } + fn input_schema(&self) -> serde_json::Value { let schema = schemars::schema_for!(DiagnosticsToolInput); serde_json::to_value(&schema).unwrap() diff --git a/crates/assistant_tools/src/edit_files_tool.rs b/crates/assistant_tools/src/edit_files_tool.rs index 4f36df2901..08b275c24a 100644 --- a/crates/assistant_tools/src/edit_files_tool.rs +++ b/crates/assistant_tools/src/edit_files_tool.rs @@ -17,6 +17,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::fmt::Write; use std::sync::Arc; +use ui::IconName; use util::ResultExt; #[derive(Debug, Serialize, Deserialize, JsonSchema)] @@ -86,6 +87,10 @@ impl Tool for EditFilesTool { include_str!("./edit_files_tool/description.md").into() } + fn icon(&self) -> IconName { + IconName::Pencil + } + fn input_schema(&self) -> serde_json::Value { let schema = schemars::schema_for!(EditFilesToolInput); serde_json::to_value(&schema).unwrap() diff --git a/crates/assistant_tools/src/fetch_tool.rs b/crates/assistant_tools/src/fetch_tool.rs index 9d9d9c75ff..a9895f0fbe 100644 --- a/crates/assistant_tools/src/fetch_tool.rs +++ b/crates/assistant_tools/src/fetch_tool.rs @@ -12,6 +12,7 @@ use language_model::LanguageModelRequestMessage; use project::Project; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use ui::IconName; #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] enum ContentType { @@ -121,6 +122,10 @@ impl Tool for FetchTool { include_str!("./fetch_tool/description.md").to_string() } + fn icon(&self) -> IconName { + IconName::Globe + } + fn input_schema(&self) -> serde_json::Value { let schema = schemars::schema_for!(FetchToolInput); serde_json::to_value(&schema).unwrap() diff --git a/crates/assistant_tools/src/find_replace_file_tool.rs b/crates/assistant_tools/src/find_replace_file_tool.rs index 85ef8b92eb..d13fbff4db 100644 --- a/crates/assistant_tools/src/find_replace_file_tool.rs +++ b/crates/assistant_tools/src/find_replace_file_tool.rs @@ -6,6 +6,7 @@ use project::Project; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::{collections::HashSet, path::PathBuf, sync::Arc}; +use ui::IconName; use crate::replace::replace_exact; @@ -135,6 +136,10 @@ impl Tool for FindReplaceFileTool { include_str!("find_replace_tool/description.md").to_string() } + fn icon(&self) -> IconName { + IconName::Pencil + } + fn input_schema(&self) -> serde_json::Value { let schema = schemars::schema_for!(FindReplaceFileToolInput); serde_json::to_value(&schema).unwrap() diff --git a/crates/assistant_tools/src/list_directory_tool.rs b/crates/assistant_tools/src/list_directory_tool.rs index 813a65d450..9ceba3b129 100644 --- a/crates/assistant_tools/src/list_directory_tool.rs +++ b/crates/assistant_tools/src/list_directory_tool.rs @@ -6,6 +6,7 @@ use project::Project; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::{fmt::Write, path::Path, sync::Arc}; +use ui::IconName; #[derive(Debug, Serialize, Deserialize, JsonSchema)] pub struct ListDirectoryToolInput { @@ -49,6 +50,10 @@ impl Tool for ListDirectoryTool { include_str!("./list_directory_tool/description.md").into() } + fn icon(&self) -> IconName { + IconName::Folder + } + fn input_schema(&self) -> serde_json::Value { let schema = schemars::schema_for!(ListDirectoryToolInput); serde_json::to_value(&schema).unwrap() diff --git a/crates/assistant_tools/src/move_path_tool.rs b/crates/assistant_tools/src/move_path_tool.rs index 09b04fcad8..f54bfecf78 100644 --- a/crates/assistant_tools/src/move_path_tool.rs +++ b/crates/assistant_tools/src/move_path_tool.rs @@ -6,6 +6,7 @@ use project::Project; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::{path::Path, sync::Arc}; +use ui::IconName; #[derive(Debug, Serialize, Deserialize, JsonSchema)] pub struct MovePathToolInput { @@ -47,6 +48,10 @@ impl Tool for MovePathTool { include_str!("./move_path_tool/description.md").into() } + fn icon(&self) -> IconName { + IconName::ArrowRightLeft + } + fn input_schema(&self) -> serde_json::Value { let schema = schemars::schema_for!(MovePathToolInput); serde_json::to_value(&schema).unwrap() diff --git a/crates/assistant_tools/src/now_tool.rs b/crates/assistant_tools/src/now_tool.rs index 04219b2bab..3860504869 100644 --- a/crates/assistant_tools/src/now_tool.rs +++ b/crates/assistant_tools/src/now_tool.rs @@ -8,6 +8,7 @@ use language_model::LanguageModelRequestMessage; use project::Project; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use ui::IconName; #[derive(Debug, Serialize, Deserialize, JsonSchema)] #[serde(rename_all = "snake_case")] @@ -39,6 +40,10 @@ impl Tool for NowTool { "Returns the current datetime in RFC 3339 format. Only use this tool when the user specifically asks for it or the current task would benefit from knowing the current datetime.".into() } + fn icon(&self) -> IconName { + IconName::Info + } + fn input_schema(&self) -> serde_json::Value { let schema = schemars::schema_for!(NowToolInput); serde_json::to_value(&schema).unwrap() diff --git a/crates/assistant_tools/src/path_search_tool.rs b/crates/assistant_tools/src/path_search_tool.rs index 401489ca15..c3bdfbe4e0 100644 --- a/crates/assistant_tools/src/path_search_tool.rs +++ b/crates/assistant_tools/src/path_search_tool.rs @@ -6,6 +6,7 @@ use project::Project; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::{path::PathBuf, sync::Arc}; +use ui::IconName; use util::paths::PathMatcher; use worktree::Snapshot; @@ -47,6 +48,10 @@ impl Tool for PathSearchTool { include_str!("./path_search_tool/description.md").into() } + fn icon(&self) -> IconName { + IconName::SearchCode + } + fn input_schema(&self) -> serde_json::Value { let schema = schemars::schema_for!(PathSearchToolInput); serde_json::to_value(&schema).unwrap() diff --git a/crates/assistant_tools/src/read_file_tool.rs b/crates/assistant_tools/src/read_file_tool.rs index 550d4e64e4..4022f326cd 100644 --- a/crates/assistant_tools/src/read_file_tool.rs +++ b/crates/assistant_tools/src/read_file_tool.rs @@ -9,6 +9,7 @@ use language_model::LanguageModelRequestMessage; use project::Project; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use ui::IconName; #[derive(Debug, Serialize, Deserialize, JsonSchema)] pub struct ReadFileToolInput { @@ -52,6 +53,10 @@ impl Tool for ReadFileTool { include_str!("./read_file_tool/description.md").into() } + fn icon(&self) -> IconName { + IconName::Eye + } + fn input_schema(&self) -> serde_json::Value { let schema = schemars::schema_for!(ReadFileToolInput); serde_json::to_value(&schema).unwrap() diff --git a/crates/assistant_tools/src/regex_search_tool.rs b/crates/assistant_tools/src/regex_search_tool.rs index 57f91245c5..3bd6d26fa3 100644 --- a/crates/assistant_tools/src/regex_search_tool.rs +++ b/crates/assistant_tools/src/regex_search_tool.rs @@ -11,6 +11,7 @@ use project::{ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::{cmp, fmt::Write, sync::Arc}; +use ui::IconName; use util::paths::PathMatcher; #[derive(Debug, Serialize, Deserialize, JsonSchema)] @@ -49,6 +50,10 @@ impl Tool for RegexSearchTool { include_str!("./regex_search_tool/description.md").into() } + fn icon(&self) -> IconName { + IconName::Regex + } + fn input_schema(&self) -> serde_json::Value { let schema = schemars::schema_for!(RegexSearchToolInput); serde_json::to_value(&schema).unwrap() diff --git a/crates/assistant_tools/src/thinking_tool.rs b/crates/assistant_tools/src/thinking_tool.rs index 3d020c001a..4e87dddde5 100644 --- a/crates/assistant_tools/src/thinking_tool.rs +++ b/crates/assistant_tools/src/thinking_tool.rs @@ -7,6 +7,7 @@ use language_model::LanguageModelRequestMessage; use project::Project; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use ui::IconName; #[derive(Debug, Serialize, Deserialize, JsonSchema)] pub struct ThinkingToolInput { @@ -30,6 +31,10 @@ impl Tool for ThinkingTool { include_str!("./thinking_tool/description.md").to_string() } + fn icon(&self) -> IconName { + IconName::Brain + } + fn input_schema(&self) -> serde_json::Value { let schema = schemars::schema_for!(ThinkingToolInput); serde_json::to_value(&schema).unwrap() diff --git a/crates/context_server/Cargo.toml b/crates/context_server/Cargo.toml index 6e3feaf2ee..970089cae0 100644 --- a/crates/context_server/Cargo.toml +++ b/crates/context_server/Cargo.toml @@ -30,5 +30,6 @@ serde.workspace = true serde_json.workspace = true settings.workspace = true smol.workspace = true +ui.workspace = true url = { workspace = true, features = ["serde"] } util.workspace = true diff --git a/crates/context_server/src/context_server_tool.rs b/crates/context_server/src/context_server_tool.rs index 9cc3be1f8a..7e99abe70a 100644 --- a/crates/context_server/src/context_server_tool.rs +++ b/crates/context_server/src/context_server_tool.rs @@ -5,6 +5,7 @@ use assistant_tool::{ActionLog, Tool, ToolSource}; use gpui::{App, Entity, Task}; use language_model::LanguageModelRequestMessage; use project::Project; +use ui::IconName; use crate::manager::ContextServerManager; use crate::types; @@ -38,6 +39,10 @@ impl Tool for ContextServerTool { self.tool.description.clone().unwrap_or_default() } + fn icon(&self) -> IconName { + IconName::Cog + } + fn source(&self) -> ToolSource { ToolSource::ContextServer { id: self.server_id.clone().into(),