acp: Tool name prep (#36726)

Ben Brandt created

Prep work for deduping tool names

Release Notes:

- N/A

Change summary

crates/agent2/src/agent.rs                       |  2 
crates/agent2/src/tests/mod.rs                   | 55 ++++++++---------
crates/agent2/src/tests/test_tools.rs            | 30 ++++----
crates/agent2/src/thread.rs                      | 16 ++--
crates/agent2/src/tools.rs                       | 25 ++++++++
crates/agent2/src/tools/copy_path_tool.rs        |  8 +-
crates/agent2/src/tools/create_directory_tool.rs |  6 
crates/agent2/src/tools/delete_path_tool.rs      |  6 
crates/agent2/src/tools/diagnostics_tool.rs      |  6 
crates/agent2/src/tools/edit_file_tool.rs        | 29 +-------
crates/agent2/src/tools/fetch_tool.rs            |  6 
crates/agent2/src/tools/find_path_tool.rs        |  6 
crates/agent2/src/tools/grep_tool.rs             |  6 
crates/agent2/src/tools/list_directory_tool.rs   |  6 
crates/agent2/src/tools/move_path_tool.rs        |  6 
crates/agent2/src/tools/now_tool.rs              |  6 
crates/agent2/src/tools/open_tool.rs             |  6 
crates/agent2/src/tools/read_file_tool.rs        |  6 
crates/agent2/src/tools/terminal_tool.rs         |  6 
crates/agent2/src/tools/thinking_tool.rs         |  6 
crates/agent2/src/tools/web_search_tool.rs       |  6 
21 files changed, 126 insertions(+), 123 deletions(-)

Detailed changes

crates/agent2/src/agent.rs 🔗

@@ -857,7 +857,6 @@ impl acp_thread::AgentConnection for NativeAgentConnection {
         cx.spawn(async move |cx| {
             log::debug!("Starting thread creation in async context");
 
-            let action_log = cx.new(|_cx| ActionLog::new(project.clone()))?;
             // Create Thread
             let thread = agent.update(
                 cx,
@@ -878,7 +877,6 @@ impl acp_thread::AgentConnection for NativeAgentConnection {
                             project.clone(),
                             agent.project_context.clone(),
                             agent.context_server_registry.clone(),
-                            action_log.clone(),
                             agent.templates.clone(),
                             default_model,
                             cx,

crates/agent2/src/tests/mod.rs 🔗

@@ -1,6 +1,5 @@
 use super::*;
 use acp_thread::{AgentConnection, AgentModelGroupName, AgentModelList, UserMessageId};
-use action_log::ActionLog;
 use agent_client_protocol::{self as acp};
 use agent_settings::AgentProfileId;
 use anyhow::Result;
@@ -224,7 +223,7 @@ async fn test_prompt_caching(cx: &mut TestAppContext) {
 
     let tool_use = LanguageModelToolUse {
         id: "tool_1".into(),
-        name: EchoTool.name().into(),
+        name: EchoTool::name().into(),
         raw_input: json!({"text": "test"}).to_string(),
         input: json!({"text": "test"}),
         is_input_complete: true,
@@ -237,7 +236,7 @@ async fn test_prompt_caching(cx: &mut TestAppContext) {
     let completion = fake_model.pending_completions().pop().unwrap();
     let tool_result = LanguageModelToolResult {
         tool_use_id: "tool_1".into(),
-        tool_name: EchoTool.name().into(),
+        tool_name: EchoTool::name().into(),
         is_error: false,
         content: "test".into(),
         output: Some("test".into()),
@@ -307,7 +306,7 @@ async fn test_basic_tool_calls(cx: &mut TestAppContext) {
     // Test a tool calls that's likely to complete *after* streaming stops.
     let events = thread
         .update(cx, |thread, cx| {
-            thread.remove_tool(&AgentTool::name(&EchoTool));
+            thread.remove_tool(&EchoTool::name());
             thread.add_tool(DelayTool);
             thread.send(
                 UserMessageId::new(),
@@ -411,7 +410,7 @@ async fn test_tool_authorization(cx: &mut TestAppContext) {
     fake_model.send_last_completion_stream_event(LanguageModelCompletionEvent::ToolUse(
         LanguageModelToolUse {
             id: "tool_id_1".into(),
-            name: ToolRequiringPermission.name().into(),
+            name: ToolRequiringPermission::name().into(),
             raw_input: "{}".into(),
             input: json!({}),
             is_input_complete: true,
@@ -420,7 +419,7 @@ async fn test_tool_authorization(cx: &mut TestAppContext) {
     fake_model.send_last_completion_stream_event(LanguageModelCompletionEvent::ToolUse(
         LanguageModelToolUse {
             id: "tool_id_2".into(),
-            name: ToolRequiringPermission.name().into(),
+            name: ToolRequiringPermission::name().into(),
             raw_input: "{}".into(),
             input: json!({}),
             is_input_complete: true,
@@ -451,14 +450,14 @@ async fn test_tool_authorization(cx: &mut TestAppContext) {
         vec![
             language_model::MessageContent::ToolResult(LanguageModelToolResult {
                 tool_use_id: tool_call_auth_1.tool_call.id.0.to_string().into(),
-                tool_name: ToolRequiringPermission.name().into(),
+                tool_name: ToolRequiringPermission::name().into(),
                 is_error: false,
                 content: "Allowed".into(),
                 output: Some("Allowed".into())
             }),
             language_model::MessageContent::ToolResult(LanguageModelToolResult {
                 tool_use_id: tool_call_auth_2.tool_call.id.0.to_string().into(),
-                tool_name: ToolRequiringPermission.name().into(),
+                tool_name: ToolRequiringPermission::name().into(),
                 is_error: true,
                 content: "Permission to run tool denied by user".into(),
                 output: None
@@ -470,7 +469,7 @@ async fn test_tool_authorization(cx: &mut TestAppContext) {
     fake_model.send_last_completion_stream_event(LanguageModelCompletionEvent::ToolUse(
         LanguageModelToolUse {
             id: "tool_id_3".into(),
-            name: ToolRequiringPermission.name().into(),
+            name: ToolRequiringPermission::name().into(),
             raw_input: "{}".into(),
             input: json!({}),
             is_input_complete: true,
@@ -492,7 +491,7 @@ async fn test_tool_authorization(cx: &mut TestAppContext) {
         vec![language_model::MessageContent::ToolResult(
             LanguageModelToolResult {
                 tool_use_id: tool_call_auth_3.tool_call.id.0.to_string().into(),
-                tool_name: ToolRequiringPermission.name().into(),
+                tool_name: ToolRequiringPermission::name().into(),
                 is_error: false,
                 content: "Allowed".into(),
                 output: Some("Allowed".into())
@@ -504,7 +503,7 @@ async fn test_tool_authorization(cx: &mut TestAppContext) {
     fake_model.send_last_completion_stream_event(LanguageModelCompletionEvent::ToolUse(
         LanguageModelToolUse {
             id: "tool_id_4".into(),
-            name: ToolRequiringPermission.name().into(),
+            name: ToolRequiringPermission::name().into(),
             raw_input: "{}".into(),
             input: json!({}),
             is_input_complete: true,
@@ -519,7 +518,7 @@ async fn test_tool_authorization(cx: &mut TestAppContext) {
         vec![language_model::MessageContent::ToolResult(
             LanguageModelToolResult {
                 tool_use_id: "tool_id_4".into(),
-                tool_name: ToolRequiringPermission.name().into(),
+                tool_name: ToolRequiringPermission::name().into(),
                 is_error: false,
                 content: "Allowed".into(),
                 output: Some("Allowed".into())
@@ -571,7 +570,7 @@ async fn test_resume_after_tool_use_limit(cx: &mut TestAppContext) {
     cx.run_until_parked();
     let tool_use = LanguageModelToolUse {
         id: "tool_id_1".into(),
-        name: EchoTool.name().into(),
+        name: EchoTool::name().into(),
         raw_input: "{}".into(),
         input: serde_json::to_value(&EchoToolInput { text: "def".into() }).unwrap(),
         is_input_complete: true,
@@ -584,7 +583,7 @@ async fn test_resume_after_tool_use_limit(cx: &mut TestAppContext) {
     let completion = fake_model.pending_completions().pop().unwrap();
     let tool_result = LanguageModelToolResult {
         tool_use_id: "tool_id_1".into(),
-        tool_name: EchoTool.name().into(),
+        tool_name: EchoTool::name().into(),
         is_error: false,
         content: "def".into(),
         output: Some("def".into()),
@@ -690,14 +689,14 @@ async fn test_send_after_tool_use_limit(cx: &mut TestAppContext) {
 
     let tool_use = LanguageModelToolUse {
         id: "tool_id_1".into(),
-        name: EchoTool.name().into(),
+        name: EchoTool::name().into(),
         raw_input: "{}".into(),
         input: serde_json::to_value(&EchoToolInput { text: "def".into() }).unwrap(),
         is_input_complete: true,
     };
     let tool_result = LanguageModelToolResult {
         tool_use_id: "tool_id_1".into(),
-        tool_name: EchoTool.name().into(),
+        tool_name: EchoTool::name().into(),
         is_error: false,
         content: "def".into(),
         output: Some("def".into()),
@@ -874,14 +873,14 @@ async fn test_profiles(cx: &mut TestAppContext) {
                     "test-1": {
                         "name": "Test Profile 1",
                         "tools": {
-                            EchoTool.name(): true,
-                            DelayTool.name(): true,
+                            EchoTool::name(): true,
+                            DelayTool::name(): true,
                         }
                     },
                     "test-2": {
                         "name": "Test Profile 2",
                         "tools": {
-                            InfiniteTool.name(): true,
+                            InfiniteTool::name(): true,
                         }
                     }
                 }
@@ -910,7 +909,7 @@ async fn test_profiles(cx: &mut TestAppContext) {
         .iter()
         .map(|tool| tool.name.clone())
         .collect();
-    assert_eq!(tool_names, vec![DelayTool.name(), EchoTool.name()]);
+    assert_eq!(tool_names, vec![DelayTool::name(), EchoTool::name()]);
     fake_model.end_last_completion_stream();
 
     // Switch to test-2 profile, and verify that it has only the infinite tool.
@@ -929,7 +928,7 @@ async fn test_profiles(cx: &mut TestAppContext) {
         .iter()
         .map(|tool| tool.name.clone())
         .collect();
-    assert_eq!(tool_names, vec![InfiniteTool.name()]);
+    assert_eq!(tool_names, vec![InfiniteTool::name()]);
 }
 
 #[gpui::test]
@@ -1552,7 +1551,7 @@ async fn test_tool_updates_to_completion(cx: &mut TestAppContext) {
     fake_model.send_last_completion_stream_event(LanguageModelCompletionEvent::ToolUse(
         LanguageModelToolUse {
             id: "1".into(),
-            name: ThinkingTool.name().into(),
+            name: ThinkingTool::name().into(),
             raw_input: input.to_string(),
             input,
             is_input_complete: false,
@@ -1840,11 +1839,11 @@ async fn setup(cx: &mut TestAppContext, model: TestModel) -> ThreadTest {
                     "test-profile": {
                         "name": "Test Profile",
                         "tools": {
-                            EchoTool.name(): true,
-                            DelayTool.name(): true,
-                            WordListTool.name(): true,
-                            ToolRequiringPermission.name(): true,
-                            InfiniteTool.name(): true,
+                            EchoTool::name(): true,
+                            DelayTool::name(): true,
+                            WordListTool::name(): true,
+                            ToolRequiringPermission::name(): true,
+                            InfiniteTool::name(): true,
                         }
                     }
                 }
@@ -1903,13 +1902,11 @@ async fn setup(cx: &mut TestAppContext, model: TestModel) -> ThreadTest {
     let project_context = cx.new(|_cx| ProjectContext::default());
     let context_server_registry =
         cx.new(|cx| ContextServerRegistry::new(project.read(cx).context_server_store(), cx));
-    let action_log = cx.new(|_| ActionLog::new(project.clone()));
     let thread = cx.new(|cx| {
         Thread::new(
             project,
             project_context.clone(),
             context_server_registry,
-            action_log,
             templates,
             Some(model.clone()),
             cx,

crates/agent2/src/tests/test_tools.rs 🔗

@@ -16,11 +16,11 @@ impl AgentTool for EchoTool {
     type Input = EchoToolInput;
     type Output = String;
 
-    fn name(&self) -> SharedString {
-        "echo".into()
+    fn name() -> &'static str {
+        "echo"
     }
 
-    fn kind(&self) -> acp::ToolKind {
+    fn kind() -> acp::ToolKind {
         acp::ToolKind::Other
     }
 
@@ -51,8 +51,8 @@ impl AgentTool for DelayTool {
     type Input = DelayToolInput;
     type Output = String;
 
-    fn name(&self) -> SharedString {
-        "delay".into()
+    fn name() -> &'static str {
+        "delay"
     }
 
     fn initial_title(&self, input: Result<Self::Input, serde_json::Value>) -> SharedString {
@@ -63,7 +63,7 @@ impl AgentTool for DelayTool {
         }
     }
 
-    fn kind(&self) -> acp::ToolKind {
+    fn kind() -> acp::ToolKind {
         acp::ToolKind::Other
     }
 
@@ -92,11 +92,11 @@ impl AgentTool for ToolRequiringPermission {
     type Input = ToolRequiringPermissionInput;
     type Output = String;
 
-    fn name(&self) -> SharedString {
-        "tool_requiring_permission".into()
+    fn name() -> &'static str {
+        "tool_requiring_permission"
     }
 
-    fn kind(&self) -> acp::ToolKind {
+    fn kind() -> acp::ToolKind {
         acp::ToolKind::Other
     }
 
@@ -127,11 +127,11 @@ impl AgentTool for InfiniteTool {
     type Input = InfiniteToolInput;
     type Output = String;
 
-    fn name(&self) -> SharedString {
-        "infinite".into()
+    fn name() -> &'static str {
+        "infinite"
     }
 
-    fn kind(&self) -> acp::ToolKind {
+    fn kind() -> acp::ToolKind {
         acp::ToolKind::Other
     }
 
@@ -178,11 +178,11 @@ impl AgentTool for WordListTool {
     type Input = WordListInput;
     type Output = String;
 
-    fn name(&self) -> SharedString {
-        "word_list".into()
+    fn name() -> &'static str {
+        "word_list"
     }
 
-    fn kind(&self) -> acp::ToolKind {
+    fn kind() -> acp::ToolKind {
         acp::ToolKind::Other
     }
 

crates/agent2/src/thread.rs 🔗

@@ -544,12 +544,12 @@ impl Thread {
         project: Entity<Project>,
         project_context: Entity<ProjectContext>,
         context_server_registry: Entity<ContextServerRegistry>,
-        action_log: Entity<ActionLog>,
         templates: Arc<Templates>,
         model: Option<Arc<dyn LanguageModel>>,
         cx: &mut Context<Self>,
     ) -> Self {
         let profile_id = AgentSettings::get_global(cx).default_profile.clone();
+        let action_log = cx.new(|_cx| ActionLog::new(project.clone()));
         Self {
             id: acp::SessionId(uuid::Uuid::new_v4().to_string().into()),
             prompt_id: PromptId::new(),
@@ -959,11 +959,11 @@ impl Thread {
         ));
         self.add_tool(TerminalTool::new(self.project.clone(), cx));
         self.add_tool(ThinkingTool);
-        self.add_tool(WebSearchTool); // TODO: Enable this only if it's a zed model.
+        self.add_tool(WebSearchTool);
     }
 
-    pub fn add_tool(&mut self, tool: impl AgentTool) {
-        self.tools.insert(tool.name(), tool.erase());
+    pub fn add_tool<T: AgentTool>(&mut self, tool: T) {
+        self.tools.insert(T::name().into(), tool.erase());
     }
 
     pub fn remove_tool(&mut self, name: &str) -> bool {
@@ -1989,7 +1989,7 @@ where
     type Input: for<'de> Deserialize<'de> + Serialize + JsonSchema;
     type Output: for<'de> Deserialize<'de> + Serialize + Into<LanguageModelToolResultContent>;
 
-    fn name(&self) -> SharedString;
+    fn name() -> &'static str;
 
     fn description(&self) -> SharedString {
         let schema = schemars::schema_for!(Self::Input);
@@ -2001,7 +2001,7 @@ where
         )
     }
 
-    fn kind(&self) -> acp::ToolKind;
+    fn kind() -> acp::ToolKind;
 
     /// The initial tool title to display. Can be updated during the tool run.
     fn initial_title(&self, input: Result<Self::Input, serde_json::Value>) -> SharedString;
@@ -2077,7 +2077,7 @@ where
     T: AgentTool,
 {
     fn name(&self) -> SharedString {
-        self.0.name()
+        T::name().into()
     }
 
     fn description(&self) -> SharedString {
@@ -2085,7 +2085,7 @@ where
     }
 
     fn kind(&self) -> agent_client_protocol::ToolKind {
-        self.0.kind()
+        T::kind()
     }
 
     fn initial_title(&self, input: serde_json::Value) -> SharedString {

crates/agent2/src/tools.rs 🔗

@@ -16,6 +16,29 @@ mod terminal_tool;
 mod thinking_tool;
 mod web_search_tool;
 
+/// A list of all built in tool names, for use in deduplicating MCP tool names
+pub fn default_tool_names() -> impl Iterator<Item = &'static str> {
+    [
+        CopyPathTool::name(),
+        CreateDirectoryTool::name(),
+        DeletePathTool::name(),
+        DiagnosticsTool::name(),
+        EditFileTool::name(),
+        FetchTool::name(),
+        FindPathTool::name(),
+        GrepTool::name(),
+        ListDirectoryTool::name(),
+        MovePathTool::name(),
+        NowTool::name(),
+        OpenTool::name(),
+        ReadFileTool::name(),
+        TerminalTool::name(),
+        ThinkingTool::name(),
+        WebSearchTool::name(),
+    ]
+    .into_iter()
+}
+
 pub use context_server_registry::*;
 pub use copy_path_tool::*;
 pub use create_directory_tool::*;
@@ -33,3 +56,5 @@ pub use read_file_tool::*;
 pub use terminal_tool::*;
 pub use thinking_tool::*;
 pub use web_search_tool::*;
+
+use crate::AgentTool;

crates/agent2/src/tools/copy_path_tool.rs 🔗

@@ -1,7 +1,7 @@
 use crate::{AgentTool, ToolCallEventStream};
 use agent_client_protocol::ToolKind;
 use anyhow::{Context as _, Result, anyhow};
-use gpui::{App, AppContext, Entity, SharedString, Task};
+use gpui::{App, AppContext, Entity, Task};
 use project::Project;
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
@@ -50,11 +50,11 @@ impl AgentTool for CopyPathTool {
     type Input = CopyPathToolInput;
     type Output = String;
 
-    fn name(&self) -> SharedString {
-        "copy_path".into()
+    fn name() -> &'static str {
+        "copy_path"
     }
 
-    fn kind(&self) -> ToolKind {
+    fn kind() -> ToolKind {
         ToolKind::Move
     }
 

crates/agent2/src/tools/create_directory_tool.rs 🔗

@@ -41,11 +41,11 @@ impl AgentTool for CreateDirectoryTool {
     type Input = CreateDirectoryToolInput;
     type Output = String;
 
-    fn name(&self) -> SharedString {
-        "create_directory".into()
+    fn name() -> &'static str {
+        "create_directory"
     }
 
-    fn kind(&self) -> ToolKind {
+    fn kind() -> ToolKind {
         ToolKind::Read
     }
 

crates/agent2/src/tools/delete_path_tool.rs 🔗

@@ -44,11 +44,11 @@ impl AgentTool for DeletePathTool {
     type Input = DeletePathToolInput;
     type Output = String;
 
-    fn name(&self) -> SharedString {
-        "delete_path".into()
+    fn name() -> &'static str {
+        "delete_path"
     }
 
-    fn kind(&self) -> ToolKind {
+    fn kind() -> ToolKind {
         ToolKind::Delete
     }
 

crates/agent2/src/tools/diagnostics_tool.rs 🔗

@@ -63,11 +63,11 @@ impl AgentTool for DiagnosticsTool {
     type Input = DiagnosticsToolInput;
     type Output = String;
 
-    fn name(&self) -> SharedString {
-        "diagnostics".into()
+    fn name() -> &'static str {
+        "diagnostics"
     }
 
-    fn kind(&self) -> acp::ToolKind {
+    fn kind() -> acp::ToolKind {
         acp::ToolKind::Read
     }
 

crates/agent2/src/tools/edit_file_tool.rs 🔗

@@ -186,11 +186,11 @@ impl AgentTool for EditFileTool {
     type Input = EditFileToolInput;
     type Output = EditFileToolOutput;
 
-    fn name(&self) -> SharedString {
-        "edit_file".into()
+    fn name() -> &'static str {
+        "edit_file"
     }
 
-    fn kind(&self) -> acp::ToolKind {
+    fn kind() -> acp::ToolKind {
         acp::ToolKind::Edit
     }
 
@@ -517,7 +517,6 @@ fn resolve_path(
 mod tests {
     use super::*;
     use crate::{ContextServerRegistry, Templates};
-    use action_log::ActionLog;
     use client::TelemetrySettings;
     use fs::Fs;
     use gpui::{TestAppContext, UpdateGlobal};
@@ -535,7 +534,6 @@ mod tests {
         fs.insert_tree("/root", json!({})).await;
         let project = Project::test(fs.clone(), [path!("/root").as_ref()], cx).await;
         let language_registry = project.read_with(cx, |project, _cx| project.languages().clone());
-        let action_log = cx.new(|_| ActionLog::new(project.clone()));
         let context_server_registry =
             cx.new(|cx| ContextServerRegistry::new(project.read(cx).context_server_store(), cx));
         let model = Arc::new(FakeLanguageModel::default());
@@ -544,7 +542,6 @@ mod tests {
                 project,
                 cx.new(|_cx| ProjectContext::default()),
                 context_server_registry,
-                action_log,
                 Templates::new(),
                 Some(model),
                 cx,
@@ -735,7 +732,6 @@ mod tests {
             }
         });
 
-        let action_log = cx.new(|_| ActionLog::new(project.clone()));
         let context_server_registry =
             cx.new(|cx| ContextServerRegistry::new(project.read(cx).context_server_store(), cx));
         let model = Arc::new(FakeLanguageModel::default());
@@ -744,7 +740,6 @@ mod tests {
                 project,
                 cx.new(|_cx| ProjectContext::default()),
                 context_server_registry,
-                action_log.clone(),
                 Templates::new(),
                 Some(model.clone()),
                 cx,
@@ -801,7 +796,9 @@ mod tests {
             "Code should be formatted when format_on_save is enabled"
         );
 
-        let stale_buffer_count = action_log.read_with(cx, |log, cx| log.stale_buffers(cx).count());
+        let stale_buffer_count = thread
+            .read_with(cx, |thread, _cx| thread.action_log.clone())
+            .read_with(cx, |log, cx| log.stale_buffers(cx).count());
 
         assert_eq!(
             stale_buffer_count, 0,
@@ -879,14 +876,12 @@ mod tests {
         let context_server_registry =
             cx.new(|cx| ContextServerRegistry::new(project.read(cx).context_server_store(), cx));
         let language_registry = project.read_with(cx, |project, _cx| project.languages().clone());
-        let action_log = cx.new(|_| ActionLog::new(project.clone()));
         let model = Arc::new(FakeLanguageModel::default());
         let thread = cx.new(|cx| {
             Thread::new(
                 project,
                 cx.new(|_cx| ProjectContext::default()),
                 context_server_registry,
-                action_log.clone(),
                 Templates::new(),
                 Some(model.clone()),
                 cx,
@@ -1008,14 +1003,12 @@ mod tests {
         let context_server_registry =
             cx.new(|cx| ContextServerRegistry::new(project.read(cx).context_server_store(), cx));
         let language_registry = project.read_with(cx, |project, _cx| project.languages().clone());
-        let action_log = cx.new(|_| ActionLog::new(project.clone()));
         let model = Arc::new(FakeLanguageModel::default());
         let thread = cx.new(|cx| {
             Thread::new(
                 project,
                 cx.new(|_cx| ProjectContext::default()),
                 context_server_registry,
-                action_log.clone(),
                 Templates::new(),
                 Some(model.clone()),
                 cx,
@@ -1146,14 +1139,12 @@ mod tests {
         let language_registry = project.read_with(cx, |project, _cx| project.languages().clone());
         let context_server_registry =
             cx.new(|cx| ContextServerRegistry::new(project.read(cx).context_server_store(), cx));
-        let action_log = cx.new(|_| ActionLog::new(project.clone()));
         let model = Arc::new(FakeLanguageModel::default());
         let thread = cx.new(|cx| {
             Thread::new(
                 project,
                 cx.new(|_cx| ProjectContext::default()),
                 context_server_registry,
-                action_log.clone(),
                 Templates::new(),
                 Some(model.clone()),
                 cx,
@@ -1254,7 +1245,6 @@ mod tests {
         )
         .await;
         let language_registry = project.read_with(cx, |project, _cx| project.languages().clone());
-        let action_log = cx.new(|_| ActionLog::new(project.clone()));
         let context_server_registry =
             cx.new(|cx| ContextServerRegistry::new(project.read(cx).context_server_store(), cx));
         let model = Arc::new(FakeLanguageModel::default());
@@ -1263,7 +1253,6 @@ mod tests {
                 project.clone(),
                 cx.new(|_cx| ProjectContext::default()),
                 context_server_registry.clone(),
-                action_log.clone(),
                 Templates::new(),
                 Some(model.clone()),
                 cx,
@@ -1336,7 +1325,6 @@ mod tests {
         .await;
         let project = Project::test(fs.clone(), [path!("/project").as_ref()], cx).await;
         let language_registry = project.read_with(cx, |project, _cx| project.languages().clone());
-        let action_log = cx.new(|_| ActionLog::new(project.clone()));
         let context_server_registry =
             cx.new(|cx| ContextServerRegistry::new(project.read(cx).context_server_store(), cx));
         let model = Arc::new(FakeLanguageModel::default());
@@ -1345,7 +1333,6 @@ mod tests {
                 project.clone(),
                 cx.new(|_cx| ProjectContext::default()),
                 context_server_registry.clone(),
-                action_log.clone(),
                 Templates::new(),
                 Some(model.clone()),
                 cx,
@@ -1421,7 +1408,6 @@ mod tests {
         .await;
         let project = Project::test(fs.clone(), [path!("/project").as_ref()], cx).await;
         let language_registry = project.read_with(cx, |project, _cx| project.languages().clone());
-        let action_log = cx.new(|_| ActionLog::new(project.clone()));
         let context_server_registry =
             cx.new(|cx| ContextServerRegistry::new(project.read(cx).context_server_store(), cx));
         let model = Arc::new(FakeLanguageModel::default());
@@ -1430,7 +1416,6 @@ mod tests {
                 project.clone(),
                 cx.new(|_cx| ProjectContext::default()),
                 context_server_registry.clone(),
-                action_log.clone(),
                 Templates::new(),
                 Some(model.clone()),
                 cx,
@@ -1503,7 +1488,6 @@ mod tests {
         let fs = project::FakeFs::new(cx.executor());
         let project = Project::test(fs.clone(), [path!("/project").as_ref()], cx).await;
         let language_registry = project.read_with(cx, |project, _cx| project.languages().clone());
-        let action_log = cx.new(|_| ActionLog::new(project.clone()));
         let context_server_registry =
             cx.new(|cx| ContextServerRegistry::new(project.read(cx).context_server_store(), cx));
         let model = Arc::new(FakeLanguageModel::default());
@@ -1512,7 +1496,6 @@ mod tests {
                 project.clone(),
                 cx.new(|_cx| ProjectContext::default()),
                 context_server_registry,
-                action_log.clone(),
                 Templates::new(),
                 Some(model.clone()),
                 cx,

crates/agent2/src/tools/fetch_tool.rs 🔗

@@ -118,11 +118,11 @@ impl AgentTool for FetchTool {
     type Input = FetchToolInput;
     type Output = String;
 
-    fn name(&self) -> SharedString {
-        "fetch".into()
+    fn name() -> &'static str {
+        "fetch"
     }
 
-    fn kind(&self) -> acp::ToolKind {
+    fn kind() -> acp::ToolKind {
         acp::ToolKind::Fetch
     }
 

crates/agent2/src/tools/find_path_tool.rs 🔗

@@ -85,11 +85,11 @@ impl AgentTool for FindPathTool {
     type Input = FindPathToolInput;
     type Output = FindPathToolOutput;
 
-    fn name(&self) -> SharedString {
-        "find_path".into()
+    fn name() -> &'static str {
+        "find_path"
     }
 
-    fn kind(&self) -> acp::ToolKind {
+    fn kind() -> acp::ToolKind {
         acp::ToolKind::Search
     }
 

crates/agent2/src/tools/grep_tool.rs 🔗

@@ -67,11 +67,11 @@ impl AgentTool for GrepTool {
     type Input = GrepToolInput;
     type Output = String;
 
-    fn name(&self) -> SharedString {
-        "grep".into()
+    fn name() -> &'static str {
+        "grep"
     }
 
-    fn kind(&self) -> acp::ToolKind {
+    fn kind() -> acp::ToolKind {
         acp::ToolKind::Search
     }
 

crates/agent2/src/tools/list_directory_tool.rs 🔗

@@ -51,11 +51,11 @@ impl AgentTool for ListDirectoryTool {
     type Input = ListDirectoryToolInput;
     type Output = String;
 
-    fn name(&self) -> SharedString {
-        "list_directory".into()
+    fn name() -> &'static str {
+        "list_directory"
     }
 
-    fn kind(&self) -> ToolKind {
+    fn kind() -> ToolKind {
         ToolKind::Read
     }
 

crates/agent2/src/tools/move_path_tool.rs 🔗

@@ -52,11 +52,11 @@ impl AgentTool for MovePathTool {
     type Input = MovePathToolInput;
     type Output = String;
 
-    fn name(&self) -> SharedString {
-        "move_path".into()
+    fn name() -> &'static str {
+        "move_path"
     }
 
-    fn kind(&self) -> ToolKind {
+    fn kind() -> ToolKind {
         ToolKind::Move
     }
 

crates/agent2/src/tools/now_tool.rs 🔗

@@ -32,11 +32,11 @@ impl AgentTool for NowTool {
     type Input = NowToolInput;
     type Output = String;
 
-    fn name(&self) -> SharedString {
-        "now".into()
+    fn name() -> &'static str {
+        "now"
     }
 
-    fn kind(&self) -> acp::ToolKind {
+    fn kind() -> acp::ToolKind {
         acp::ToolKind::Other
     }
 

crates/agent2/src/tools/open_tool.rs 🔗

@@ -37,11 +37,11 @@ impl AgentTool for OpenTool {
     type Input = OpenToolInput;
     type Output = String;
 
-    fn name(&self) -> SharedString {
-        "open".into()
+    fn name() -> &'static str {
+        "open"
     }
 
-    fn kind(&self) -> ToolKind {
+    fn kind() -> ToolKind {
         ToolKind::Execute
     }
 

crates/agent2/src/tools/read_file_tool.rs 🔗

@@ -59,11 +59,11 @@ impl AgentTool for ReadFileTool {
     type Input = ReadFileToolInput;
     type Output = LanguageModelToolResultContent;
 
-    fn name(&self) -> SharedString {
-        "read_file".into()
+    fn name() -> &'static str {
+        "read_file"
     }
 
-    fn kind(&self) -> acp::ToolKind {
+    fn kind() -> acp::ToolKind {
         acp::ToolKind::Read
     }
 

crates/agent2/src/tools/terminal_tool.rs 🔗

@@ -63,11 +63,11 @@ impl AgentTool for TerminalTool {
     type Input = TerminalToolInput;
     type Output = String;
 
-    fn name(&self) -> SharedString {
-        "terminal".into()
+    fn name() -> &'static str {
+        "terminal"
     }
 
-    fn kind(&self) -> acp::ToolKind {
+    fn kind() -> acp::ToolKind {
         acp::ToolKind::Execute
     }
 

crates/agent2/src/tools/thinking_tool.rs 🔗

@@ -21,11 +21,11 @@ impl AgentTool for ThinkingTool {
     type Input = ThinkingToolInput;
     type Output = String;
 
-    fn name(&self) -> SharedString {
-        "thinking".into()
+    fn name() -> &'static str {
+        "thinking"
     }
 
-    fn kind(&self) -> acp::ToolKind {
+    fn kind() -> acp::ToolKind {
         acp::ToolKind::Think
     }
 

crates/agent2/src/tools/web_search_tool.rs 🔗

@@ -40,11 +40,11 @@ impl AgentTool for WebSearchTool {
     type Input = WebSearchToolInput;
     type Output = WebSearchToolOutput;
 
-    fn name(&self) -> SharedString {
-        "web_search".into()
+    fn name() -> &'static str {
+        "web_search"
     }
 
-    fn kind(&self) -> acp::ToolKind {
+    fn kind() -> acp::ToolKind {
         acp::ToolKind::Fetch
     }