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