diff --git a/Cargo.lock b/Cargo.lock index 607e0f4976314143756956d969171adea557cc78..8e693f85878318342a100614475d293c5544a816 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 8da640f9f4ec7350a800eb86a9fa30a9d0444d01..cd6a4f342c40f5b9a9f66785f97d88c7c74ac92a 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 9a5cfcef67294e8eea1a119002ad8eef491f6966..d13c711d85adb3540d044f0ea5a41cc2053be7f5 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 040a906bf3cbcae70389c075a9048aa0273e319a..a34cd95dfd956396cf0d82e4fa0b58b4b5dd1ea1 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 20fdb054390fe83d7abce9f19be5b045055bfc0c..2684e62211faa2271e852ff42b49fe7ecaf4e2e2 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 27a021ee1207545d6c1a6af46a8670857626ed43..19cf5c198cb39ab0158b0605e1c94df355c60a6f 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 e0f325102eaef090aa3f667287a5901d8dba767d..d4cb85421b641f270c8bcb6a6036f224c458f849 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 d34db2f1c277c24fe9d719f2e5e619a83c83fadf..dc1b5c0f0395dd9cb7f57062bc3335512c5d26b8 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 cc13d34e80d523939a0b0bc4366915f924c0cf10..3bd55e6c3a5af9d49e93ef281b1f6ad485f89c7c 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 95aec472a56744e77113afb39ebff8fea8f87d67..a3638a431fb996c04598f17190e20a34b441fc01 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 4f36df2901d06b9e9e80f2151ca1d38c68f02b62..08b275c24af20133caf47f167dfcfc8233399c66 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 9d9d9c75ffdebd0ebd2ada33fc6b6b7bc4fa3618..a9895f0fbef9f1efd37f1683689c3fdfb506db3d 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 85ef8b92eb7b6fa4ba62fe8d1b71e3763ea2b4f0..d13fbff4db88f5f10922daf7c493d2a69946e7a1 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 813a65d45066511a2fa425fb2d58aab26765f665..9ceba3b129c9e45cc1674a205aed84b89536a2ff 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 09b04fcad8258f92aa29abde171ae59b1e1fead2..f54bfecf783ad8719dde1f2bb27dbfeb550fd034 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 04219b2bab8ef10ef0f21ed857679d426c745fcd..3860504869bf16e7639948ab6debca27728fb725 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 401489ca15052badf1b595f9110b9af6cf1eb177..c3bdfbe4e02eba872f6018aeaf177209a648166b 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 550d4e64e46e45dd66180b58009a55edd82559a2..4022f326cdc6ffaa9f451aedddbf448d9897e106 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 57f91245c5936b9eb53a9a008985f3fc8b11977a..3bd6d26fa3e5582ac18d2e303a38c41b91c6e1bd 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 3d020c001a929b5a0aac0f1b614809c66314d413..4e87dddde59e5ada02f65c8bddb59153283e3fc9 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 6e3feaf2ee43471a5b6d0e72dfb022fe13df63e6..970089cae03c2204fb55b409aaf7463dff635ac6 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 9cc3be1f8acb626e71d46b2550d2ed4ed2d12f69..7e99abe70a34688ec624544eaf3d2c7782beabcd 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(),