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