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 read_file_tool;
15mod schema;
16mod templates;
17mod terminal_tool;
18mod thinking_tool;
19mod ui;
20mod web_search_tool;
21
22use std::sync::Arc;
23
24use assistant_tool::ToolRegistry;
25use copy_path_tool::CopyPathTool;
26use gpui::{App, Entity};
27use http_client::HttpClientWithUrl;
28use language_model::LanguageModelRegistry;
29use move_path_tool::MovePathTool;
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::find_path_tool::FindPathTool;
40use crate::grep_tool::GrepTool;
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 open_tool::OpenTool;
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(FindPathTool);
65 registry.register_tool(ReadFileTool);
66 registry.register_tool(GrepTool);
67 registry.register_tool(ThinkingTool);
68 registry.register_tool(FetchTool::new(http_client));
69 registry.register_tool(EditFileTool);
70
71 register_web_search_tool(&LanguageModelRegistry::global(cx), cx);
72 cx.subscribe(
73 &LanguageModelRegistry::global(cx),
74 move |registry, event, cx| match event {
75 language_model::Event::DefaultModelChanged => {
76 register_web_search_tool(®istry, cx);
77 }
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 .map_or(false, |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 })
130 );
131 }
132
133 #[gpui::test]
134 fn test_builtin_tool_schema_compatibility(cx: &mut App) {
135 settings::init(cx);
136 AgentSettings::register(cx);
137
138 let client = Client::new(
139 Arc::new(FakeSystemClock::new()),
140 FakeHttpClient::with_200_response(),
141 cx,
142 );
143 language_model::init(client.clone(), cx);
144 crate::init(client.http_client(), cx);
145
146 for tool in ToolRegistry::global(cx).tools() {
147 let actual_schema = tool
148 .input_schema(language_model::LanguageModelToolSchemaFormat::JsonSchemaSubset)
149 .unwrap();
150 let mut expected_schema = actual_schema.clone();
151 assistant_tool::adapt_schema_to_format(
152 &mut expected_schema,
153 language_model::LanguageModelToolSchemaFormat::JsonSchemaSubset,
154 )
155 .unwrap();
156
157 let error_message = format!(
158 "Tool schema for `{}` is not compatible with `language_model::LanguageModelToolSchemaFormat::JsonSchemaSubset` (Gemini Models).\n\
159 Are you using `schema::json_schema_for<T>(format)` to generate the schema?",
160 tool.name(),
161 );
162
163 assert_eq!(actual_schema, expected_schema, "{}", error_message)
164 }
165 }
166}