1mod copy_path_tool;
2mod create_directory_tool;
3mod delete_path_tool;
4mod diagnostics_tool;
5pub mod edit_agent;
6mod edit_file_tool;
7mod fetch_tool;
8mod find_path_tool;
9mod grep_tool;
10mod list_directory_tool;
11mod move_path_tool;
12mod now_tool;
13mod open_tool;
14mod project_notifications_tool;
15mod read_file_tool;
16mod schema;
17pub mod templates;
18mod terminal_tool;
19mod thinking_tool;
20mod ui;
21mod web_search_tool;
22
23use assistant_tool::ToolRegistry;
24use copy_path_tool::CopyPathTool;
25use gpui::{App, Entity};
26use http_client::HttpClientWithUrl;
27use language_model::LanguageModelRegistry;
28use move_path_tool::MovePathTool;
29use std::sync::Arc;
30use web_search_tool::WebSearchTool;
31
32pub(crate) use templates::*;
33
34use crate::create_directory_tool::CreateDirectoryTool;
35use crate::delete_path_tool::DeletePathTool;
36use crate::diagnostics_tool::DiagnosticsTool;
37use crate::edit_file_tool::EditFileTool;
38use crate::fetch_tool::FetchTool;
39use crate::list_directory_tool::ListDirectoryTool;
40use crate::now_tool::NowTool;
41use crate::thinking_tool::ThinkingTool;
42
43pub use edit_file_tool::{EditFileMode, EditFileToolInput};
44pub use find_path_tool::*;
45pub use grep_tool::{GrepTool, GrepToolInput};
46pub use open_tool::OpenTool;
47pub use project_notifications_tool::ProjectNotificationsTool;
48pub use read_file_tool::{ReadFileTool, ReadFileToolInput};
49pub use terminal_tool::TerminalTool;
50
51pub fn init(http_client: Arc<HttpClientWithUrl>, cx: &mut App) {
52 assistant_tool::init(cx);
53
54 let registry = ToolRegistry::global(cx);
55 registry.register_tool(TerminalTool::new(cx));
56 registry.register_tool(CreateDirectoryTool);
57 registry.register_tool(CopyPathTool);
58 registry.register_tool(DeletePathTool);
59 registry.register_tool(MovePathTool);
60 registry.register_tool(DiagnosticsTool);
61 registry.register_tool(ListDirectoryTool);
62 registry.register_tool(NowTool);
63 registry.register_tool(OpenTool);
64 registry.register_tool(ProjectNotificationsTool);
65 registry.register_tool(FindPathTool);
66 registry.register_tool(ReadFileTool);
67 registry.register_tool(GrepTool);
68 registry.register_tool(ThinkingTool);
69 registry.register_tool(FetchTool::new(http_client));
70 registry.register_tool(EditFileTool);
71
72 register_web_search_tool(&LanguageModelRegistry::global(cx), cx);
73 cx.subscribe(
74 &LanguageModelRegistry::global(cx),
75 move |registry, event, cx| {
76 if let language_model::Event::DefaultModelChanged = event {
77 register_web_search_tool(®istry, cx);
78 }
79 },
80 )
81 .detach();
82}
83
84fn register_web_search_tool(registry: &Entity<LanguageModelRegistry>, cx: &mut App) {
85 let using_zed_provider = registry
86 .read(cx)
87 .default_model()
88 .is_some_and(|default| default.is_provided_by_zed());
89 if using_zed_provider {
90 ToolRegistry::global(cx).register_tool(WebSearchTool);
91 } else {
92 ToolRegistry::global(cx).unregister_tool(WebSearchTool);
93 }
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99 use agent_settings::AgentSettings;
100 use client::Client;
101 use clock::FakeSystemClock;
102 use http_client::FakeHttpClient;
103 use schemars::JsonSchema;
104 use serde::Serialize;
105 use settings::Settings;
106
107 #[test]
108 fn test_json_schema() {
109 #[derive(Serialize, JsonSchema)]
110 struct GetWeatherTool {
111 location: String,
112 }
113
114 let schema = schema::json_schema_for::<GetWeatherTool>(
115 language_model::LanguageModelToolSchemaFormat::JsonSchema,
116 )
117 .unwrap();
118
119 assert_eq!(
120 schema,
121 serde_json::json!({
122 "type": "object",
123 "properties": {
124 "location": {
125 "type": "string"
126 }
127 },
128 "required": ["location"],
129 "additionalProperties": false
130 })
131 );
132 }
133
134 #[gpui::test]
135 fn test_builtin_tool_schema_compatibility(cx: &mut App) {
136 settings::init(cx);
137 AgentSettings::register(cx);
138
139 let client = Client::new(
140 Arc::new(FakeSystemClock::new()),
141 FakeHttpClient::with_200_response(),
142 cx,
143 );
144 language_model::init(client.clone(), cx);
145 crate::init(client.http_client(), cx);
146
147 for tool in ToolRegistry::global(cx).tools() {
148 let actual_schema = tool
149 .input_schema(language_model::LanguageModelToolSchemaFormat::JsonSchemaSubset)
150 .unwrap();
151 let mut expected_schema = actual_schema.clone();
152 assistant_tool::adapt_schema_to_format(
153 &mut expected_schema,
154 language_model::LanguageModelToolSchemaFormat::JsonSchemaSubset,
155 )
156 .unwrap();
157
158 let error_message = format!(
159 "Tool schema for `{}` is not compatible with `language_model::LanguageModelToolSchemaFormat::JsonSchemaSubset` (Gemini Models).\n\
160 Are you using `schema::json_schema_for<T>(format)` to generate the schema?",
161 tool.name(),
162 );
163
164 assert_eq!(actual_schema, expected_schema, "{}", error_message)
165 }
166 }
167}