assistant tools: Add Tool::icon method instead of matching on name (#27444)

Release Notes:

- N/A
This commit is contained in:
Agus Zubiaga 2025-03-25 15:17:36 -03:00 committed by GitHub
parent 0339d654d2
commit 46e86f003f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 98 additions and 18 deletions

2
Cargo.lock generated
View file

@ -704,6 +704,7 @@ dependencies = [
"project", "project",
"serde", "serde",
"serde_json", "serde_json",
"ui",
] ]
[[package]] [[package]]
@ -3206,6 +3207,7 @@ dependencies = [
"serde_json", "serde_json",
"settings", "settings",
"smol", "smol",
"ui",
"url", "url",
"util", "util",
] ]

View file

@ -1251,23 +1251,6 @@ impl ActiveThread {
let lighter_border = cx.theme().colors().border.opacity(0.5); 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( div().py_2().child(
v_flex() v_flex()
.rounded_lg() .rounded_lg()
@ -1293,7 +1276,7 @@ impl ActiveThread {
h_flex() h_flex()
.gap_1p5() .gap_1p5()
.child( .child(
Icon::new(tool_icon) Icon::new(tool_use.icon)
.size(IconSize::XSmall) .size(IconSize::XSmall)
.color(Color::Muted), .color(Color::Muted),
) )

View file

@ -10,6 +10,7 @@ use language_model::{
LanguageModelRequestMessage, LanguageModelToolResult, LanguageModelToolUse, LanguageModelRequestMessage, LanguageModelToolResult, LanguageModelToolUse,
LanguageModelToolUseId, MessageContent, Role, LanguageModelToolUseId, MessageContent, Role,
}; };
use ui::IconName;
use crate::thread::MessageId; use crate::thread::MessageId;
use crate::thread_store::SerializedMessage; use crate::thread_store::SerializedMessage;
@ -21,6 +22,7 @@ pub struct ToolUse {
pub ui_text: SharedString, pub ui_text: SharedString,
pub status: ToolUseStatus, pub status: ToolUseStatus,
pub input: serde_json::Value, pub input: serde_json::Value,
pub icon: ui::IconName,
} }
#[derive(Debug, Clone)] #[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 { tool_uses.push(ToolUse {
id: tool_use.id.clone(), id: tool_use.id.clone(),
name: tool_use.name.clone().into(), name: tool_use.name.clone().into(),
ui_text: self.tool_ui_label(&tool_use.name, &tool_use.input, cx), ui_text: self.tool_ui_label(&tool_use.name, &tool_use.input, cx),
input: tool_use.input.clone(), input: tool_use.input.clone(),
status, status,
icon,
}) })
} }

View file

@ -23,3 +23,4 @@ parking_lot.workspace = true
project.workspace = true project.workspace = true
serde.workspace = true serde.workspace = true
serde_json.workspace = true serde_json.workspace = true
ui.workspace = true

View file

@ -9,6 +9,7 @@ use language_model::LanguageModelRequestMessage;
use project::Project; use project::Project;
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use std::sync::Arc; use std::sync::Arc;
use ui::IconName;
pub use crate::tool_registry::*; pub use crate::tool_registry::*;
pub use crate::tool_working_set::*; pub use crate::tool_working_set::*;
@ -33,6 +34,9 @@ pub trait Tool: 'static + Send + Sync {
/// Returns the description of the tool. /// Returns the description of the tool.
fn description(&self) -> String; fn description(&self) -> String;
/// Returns the icon for the tool.
fn icon(&self) -> IconName;
/// Returns the source of the tool. /// Returns the source of the tool.
fn source(&self) -> ToolSource { fn source(&self) -> ToolSource {
ToolSource::Native ToolSource::Native

View file

@ -6,6 +6,7 @@ use project::Project;
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::sync::Arc; use std::sync::Arc;
use ui::IconName;
use util::command::new_smol_command; use util::command::new_smol_command;
#[derive(Debug, Serialize, Deserialize, JsonSchema)] #[derive(Debug, Serialize, Deserialize, JsonSchema)]
@ -31,6 +32,10 @@ impl Tool for BashTool {
include_str!("./bash_tool/description.md").to_string() include_str!("./bash_tool/description.md").to_string()
} }
fn icon(&self) -> IconName {
IconName::Terminal
}
fn input_schema(&self) -> serde_json::Value { fn input_schema(&self) -> serde_json::Value {
let schema = schemars::schema_for!(BashToolInput); let schema = schemars::schema_for!(BashToolInput);
serde_json::to_value(&schema).unwrap() serde_json::to_value(&schema).unwrap()

View file

@ -6,6 +6,7 @@ use project::Project;
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::sync::Arc; use std::sync::Arc;
use ui::IconName;
#[derive(Debug, Serialize, Deserialize, JsonSchema)] #[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct CopyPathToolInput { pub struct CopyPathToolInput {
@ -47,6 +48,10 @@ impl Tool for CopyPathTool {
include_str!("./copy_path_tool/description.md").into() include_str!("./copy_path_tool/description.md").into()
} }
fn icon(&self) -> IconName {
IconName::Clipboard
}
fn input_schema(&self) -> serde_json::Value { fn input_schema(&self) -> serde_json::Value {
let schema = schemars::schema_for!(CopyPathToolInput); let schema = schemars::schema_for!(CopyPathToolInput);
serde_json::to_value(&schema).unwrap() serde_json::to_value(&schema).unwrap()

View file

@ -6,6 +6,7 @@ use project::Project;
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::sync::Arc; use std::sync::Arc;
use ui::IconName;
#[derive(Debug, Serialize, Deserialize, JsonSchema)] #[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct CreateFileToolInput { pub struct CreateFileToolInput {
@ -44,6 +45,10 @@ impl Tool for CreateFileTool {
include_str!("./create_file_tool/description.md").into() include_str!("./create_file_tool/description.md").into()
} }
fn icon(&self) -> IconName {
IconName::File
}
fn input_schema(&self) -> serde_json::Value { fn input_schema(&self) -> serde_json::Value {
let schema = schemars::schema_for!(CreateFileToolInput); let schema = schemars::schema_for!(CreateFileToolInput);
serde_json::to_value(&schema).unwrap() serde_json::to_value(&schema).unwrap()

View file

@ -6,6 +6,7 @@ use project::Project;
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::sync::Arc; use std::sync::Arc;
use ui::IconName;
#[derive(Debug, Serialize, Deserialize, JsonSchema)] #[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct DeletePathToolInput { pub struct DeletePathToolInput {
@ -38,6 +39,10 @@ impl Tool for DeletePathTool {
include_str!("./delete_path_tool/description.md").into() include_str!("./delete_path_tool/description.md").into()
} }
fn icon(&self) -> IconName {
IconName::Trash
}
fn input_schema(&self) -> serde_json::Value { fn input_schema(&self) -> serde_json::Value {
let schema = schemars::schema_for!(DeletePathToolInput); let schema = schemars::schema_for!(DeletePathToolInput);
serde_json::to_value(&schema).unwrap() serde_json::to_value(&schema).unwrap()

View file

@ -11,6 +11,7 @@ use std::{
path::{Path, PathBuf}, path::{Path, PathBuf},
sync::Arc, sync::Arc,
}; };
use ui::IconName;
#[derive(Debug, Serialize, Deserialize, JsonSchema)] #[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct DiagnosticsToolInput { pub struct DiagnosticsToolInput {
@ -45,6 +46,10 @@ impl Tool for DiagnosticsTool {
include_str!("./diagnostics_tool/description.md").into() include_str!("./diagnostics_tool/description.md").into()
} }
fn icon(&self) -> IconName {
IconName::Warning
}
fn input_schema(&self) -> serde_json::Value { fn input_schema(&self) -> serde_json::Value {
let schema = schemars::schema_for!(DiagnosticsToolInput); let schema = schemars::schema_for!(DiagnosticsToolInput);
serde_json::to_value(&schema).unwrap() serde_json::to_value(&schema).unwrap()

View file

@ -17,6 +17,7 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt::Write; use std::fmt::Write;
use std::sync::Arc; use std::sync::Arc;
use ui::IconName;
use util::ResultExt; use util::ResultExt;
#[derive(Debug, Serialize, Deserialize, JsonSchema)] #[derive(Debug, Serialize, Deserialize, JsonSchema)]
@ -86,6 +87,10 @@ impl Tool for EditFilesTool {
include_str!("./edit_files_tool/description.md").into() include_str!("./edit_files_tool/description.md").into()
} }
fn icon(&self) -> IconName {
IconName::Pencil
}
fn input_schema(&self) -> serde_json::Value { fn input_schema(&self) -> serde_json::Value {
let schema = schemars::schema_for!(EditFilesToolInput); let schema = schemars::schema_for!(EditFilesToolInput);
serde_json::to_value(&schema).unwrap() serde_json::to_value(&schema).unwrap()

View file

@ -12,6 +12,7 @@ use language_model::LanguageModelRequestMessage;
use project::Project; use project::Project;
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use ui::IconName;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
enum ContentType { enum ContentType {
@ -121,6 +122,10 @@ impl Tool for FetchTool {
include_str!("./fetch_tool/description.md").to_string() include_str!("./fetch_tool/description.md").to_string()
} }
fn icon(&self) -> IconName {
IconName::Globe
}
fn input_schema(&self) -> serde_json::Value { fn input_schema(&self) -> serde_json::Value {
let schema = schemars::schema_for!(FetchToolInput); let schema = schemars::schema_for!(FetchToolInput);
serde_json::to_value(&schema).unwrap() serde_json::to_value(&schema).unwrap()

View file

@ -6,6 +6,7 @@ use project::Project;
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{collections::HashSet, path::PathBuf, sync::Arc}; use std::{collections::HashSet, path::PathBuf, sync::Arc};
use ui::IconName;
use crate::replace::replace_exact; use crate::replace::replace_exact;
@ -135,6 +136,10 @@ impl Tool for FindReplaceFileTool {
include_str!("find_replace_tool/description.md").to_string() include_str!("find_replace_tool/description.md").to_string()
} }
fn icon(&self) -> IconName {
IconName::Pencil
}
fn input_schema(&self) -> serde_json::Value { fn input_schema(&self) -> serde_json::Value {
let schema = schemars::schema_for!(FindReplaceFileToolInput); let schema = schemars::schema_for!(FindReplaceFileToolInput);
serde_json::to_value(&schema).unwrap() serde_json::to_value(&schema).unwrap()

View file

@ -6,6 +6,7 @@ use project::Project;
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{fmt::Write, path::Path, sync::Arc}; use std::{fmt::Write, path::Path, sync::Arc};
use ui::IconName;
#[derive(Debug, Serialize, Deserialize, JsonSchema)] #[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct ListDirectoryToolInput { pub struct ListDirectoryToolInput {
@ -49,6 +50,10 @@ impl Tool for ListDirectoryTool {
include_str!("./list_directory_tool/description.md").into() include_str!("./list_directory_tool/description.md").into()
} }
fn icon(&self) -> IconName {
IconName::Folder
}
fn input_schema(&self) -> serde_json::Value { fn input_schema(&self) -> serde_json::Value {
let schema = schemars::schema_for!(ListDirectoryToolInput); let schema = schemars::schema_for!(ListDirectoryToolInput);
serde_json::to_value(&schema).unwrap() serde_json::to_value(&schema).unwrap()

View file

@ -6,6 +6,7 @@ use project::Project;
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{path::Path, sync::Arc}; use std::{path::Path, sync::Arc};
use ui::IconName;
#[derive(Debug, Serialize, Deserialize, JsonSchema)] #[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct MovePathToolInput { pub struct MovePathToolInput {
@ -47,6 +48,10 @@ impl Tool for MovePathTool {
include_str!("./move_path_tool/description.md").into() include_str!("./move_path_tool/description.md").into()
} }
fn icon(&self) -> IconName {
IconName::ArrowRightLeft
}
fn input_schema(&self) -> serde_json::Value { fn input_schema(&self) -> serde_json::Value {
let schema = schemars::schema_for!(MovePathToolInput); let schema = schemars::schema_for!(MovePathToolInput);
serde_json::to_value(&schema).unwrap() serde_json::to_value(&schema).unwrap()

View file

@ -8,6 +8,7 @@ use language_model::LanguageModelRequestMessage;
use project::Project; use project::Project;
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use ui::IconName;
#[derive(Debug, Serialize, Deserialize, JsonSchema)] #[derive(Debug, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")] #[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() "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 { fn input_schema(&self) -> serde_json::Value {
let schema = schemars::schema_for!(NowToolInput); let schema = schemars::schema_for!(NowToolInput);
serde_json::to_value(&schema).unwrap() serde_json::to_value(&schema).unwrap()

View file

@ -6,6 +6,7 @@ use project::Project;
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{path::PathBuf, sync::Arc}; use std::{path::PathBuf, sync::Arc};
use ui::IconName;
use util::paths::PathMatcher; use util::paths::PathMatcher;
use worktree::Snapshot; use worktree::Snapshot;
@ -47,6 +48,10 @@ impl Tool for PathSearchTool {
include_str!("./path_search_tool/description.md").into() include_str!("./path_search_tool/description.md").into()
} }
fn icon(&self) -> IconName {
IconName::SearchCode
}
fn input_schema(&self) -> serde_json::Value { fn input_schema(&self) -> serde_json::Value {
let schema = schemars::schema_for!(PathSearchToolInput); let schema = schemars::schema_for!(PathSearchToolInput);
serde_json::to_value(&schema).unwrap() serde_json::to_value(&schema).unwrap()

View file

@ -9,6 +9,7 @@ use language_model::LanguageModelRequestMessage;
use project::Project; use project::Project;
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use ui::IconName;
#[derive(Debug, Serialize, Deserialize, JsonSchema)] #[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct ReadFileToolInput { pub struct ReadFileToolInput {
@ -52,6 +53,10 @@ impl Tool for ReadFileTool {
include_str!("./read_file_tool/description.md").into() include_str!("./read_file_tool/description.md").into()
} }
fn icon(&self) -> IconName {
IconName::Eye
}
fn input_schema(&self) -> serde_json::Value { fn input_schema(&self) -> serde_json::Value {
let schema = schemars::schema_for!(ReadFileToolInput); let schema = schemars::schema_for!(ReadFileToolInput);
serde_json::to_value(&schema).unwrap() serde_json::to_value(&schema).unwrap()

View file

@ -11,6 +11,7 @@ use project::{
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{cmp, fmt::Write, sync::Arc}; use std::{cmp, fmt::Write, sync::Arc};
use ui::IconName;
use util::paths::PathMatcher; use util::paths::PathMatcher;
#[derive(Debug, Serialize, Deserialize, JsonSchema)] #[derive(Debug, Serialize, Deserialize, JsonSchema)]
@ -49,6 +50,10 @@ impl Tool for RegexSearchTool {
include_str!("./regex_search_tool/description.md").into() include_str!("./regex_search_tool/description.md").into()
} }
fn icon(&self) -> IconName {
IconName::Regex
}
fn input_schema(&self) -> serde_json::Value { fn input_schema(&self) -> serde_json::Value {
let schema = schemars::schema_for!(RegexSearchToolInput); let schema = schemars::schema_for!(RegexSearchToolInput);
serde_json::to_value(&schema).unwrap() serde_json::to_value(&schema).unwrap()

View file

@ -7,6 +7,7 @@ use language_model::LanguageModelRequestMessage;
use project::Project; use project::Project;
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use ui::IconName;
#[derive(Debug, Serialize, Deserialize, JsonSchema)] #[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct ThinkingToolInput { pub struct ThinkingToolInput {
@ -30,6 +31,10 @@ impl Tool for ThinkingTool {
include_str!("./thinking_tool/description.md").to_string() include_str!("./thinking_tool/description.md").to_string()
} }
fn icon(&self) -> IconName {
IconName::Brain
}
fn input_schema(&self) -> serde_json::Value { fn input_schema(&self) -> serde_json::Value {
let schema = schemars::schema_for!(ThinkingToolInput); let schema = schemars::schema_for!(ThinkingToolInput);
serde_json::to_value(&schema).unwrap() serde_json::to_value(&schema).unwrap()

View file

@ -30,5 +30,6 @@ serde.workspace = true
serde_json.workspace = true serde_json.workspace = true
settings.workspace = true settings.workspace = true
smol.workspace = true smol.workspace = true
ui.workspace = true
url = { workspace = true, features = ["serde"] } url = { workspace = true, features = ["serde"] }
util.workspace = true util.workspace = true

View file

@ -5,6 +5,7 @@ use assistant_tool::{ActionLog, Tool, ToolSource};
use gpui::{App, Entity, Task}; use gpui::{App, Entity, Task};
use language_model::LanguageModelRequestMessage; use language_model::LanguageModelRequestMessage;
use project::Project; use project::Project;
use ui::IconName;
use crate::manager::ContextServerManager; use crate::manager::ContextServerManager;
use crate::types; use crate::types;
@ -38,6 +39,10 @@ impl Tool for ContextServerTool {
self.tool.description.clone().unwrap_or_default() self.tool.description.clone().unwrap_or_default()
} }
fn icon(&self) -> IconName {
IconName::Cog
}
fn source(&self) -> ToolSource { fn source(&self) -> ToolSource {
ToolSource::ContextServer { ToolSource::ContextServer {
id: self.server_id.clone().into(), id: self.server_id.clone().into(),