Stable cherry-pick: Change name of web search tool (#53573) (#53578)

Mikayla Maki created

Release Notes:

- N/A

Change summary

.github/workflows/run_tests.yml                         |   2 
assets/settings/default.json                            |   4 
crates/agent/src/tools/web_search_tool.rs               |   2 
crates/migrator/src/migrations.rs                       |   6 
crates/migrator/src/migrations/m_2026_04_10/settings.rs |  64 ++
crates/migrator/src/migrator.rs                         | 345 +++++++++++
crates/settings_ui/src/pages/tool_permissions_setup.rs  |   6 
docs/.doc-examples/reference.md                         |   2 
docs/src/ai/tool-permissions.md                         |   2 
docs/src/ai/tools.md                                    |   2 
tooling/xtask/src/tasks/workflows/run_tests.rs          |   2 
11 files changed, 426 insertions(+), 11 deletions(-)

Detailed changes

.github/workflows/run_tests.yml 🔗

@@ -80,7 +80,7 @@ jobs:
 
           # If assets/ changed, add crates that depend on those assets
           if echo "$CHANGED_FILES" | grep -qP '^assets/'; then
-            FILE_CHANGED_PKGS=$(printf '%s\n%s\n%s\n%s' "$FILE_CHANGED_PKGS" "settings" "storybook" "assets" | sort -u)
+            FILE_CHANGED_PKGS=$(printf '%s\n%s\n%s' "$FILE_CHANGED_PKGS" "settings" "assets" | sort -u)
           fi
 
           # Combine all changed packages

assets/settings/default.json 🔗

@@ -1062,7 +1062,7 @@
           "terminal": true,
           "thinking": true,
           "update_plan": true,
-          "web_search": true,
+          "search_web": true,
         },
       },
       "ask": {
@@ -1082,7 +1082,7 @@
           "spawn_agent": true,
           "thinking": true,
           "update_plan": true,
-          "web_search": true,
+          "search_web": true,
         },
       },
       "minimal": {

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

@@ -53,7 +53,7 @@ impl AgentTool for WebSearchTool {
     type Input = WebSearchToolInput;
     type Output = WebSearchToolOutput;
 
-    const NAME: &'static str = "web_search";
+    const NAME: &'static str = "search_web";
 
     fn kind() -> acp::ToolKind {
         acp::ToolKind::Fetch

crates/migrator/src/migrations.rs 🔗

@@ -316,3 +316,9 @@ pub(crate) mod m_2026_03_23 {
 
     pub(crate) use keymap::KEYMAP_PATTERNS;
 }
+
+pub(crate) mod m_2026_04_10 {
+    mod settings;
+
+    pub(crate) use settings::rename_web_search_to_search_web;
+}

crates/migrator/src/migrations/m_2026_04_10/settings.rs 🔗

@@ -0,0 +1,64 @@
+use anyhow::Result;
+use serde_json::Value;
+
+use crate::migrations::migrate_settings;
+
+const AGENT_KEY: &str = "agent";
+const PROFILES_KEY: &str = "profiles";
+const SETTINGS_KEY: &str = "settings";
+const TOOL_PERMISSIONS_KEY: &str = "tool_permissions";
+const TOOLS_KEY: &str = "tools";
+const OLD_TOOL_NAME: &str = "web_search";
+const NEW_TOOL_NAME: &str = "search_web";
+
+pub fn rename_web_search_to_search_web(value: &mut Value) -> Result<()> {
+    migrate_settings(value, &mut migrate_one)
+}
+
+fn migrate_one(object: &mut serde_json::Map<String, Value>) -> Result<()> {
+    migrate_agent_value(object)?;
+
+    // Root-level profiles have a `settings` wrapper after m_2026_04_01,
+    // but `migrate_settings` calls us with the profile map directly,
+    // so we need to look inside `settings` too.
+    if let Some(settings) = object.get_mut(SETTINGS_KEY).and_then(|v| v.as_object_mut()) {
+        migrate_agent_value(settings)?;
+    }
+
+    Ok(())
+}
+
+fn migrate_agent_value(object: &mut serde_json::Map<String, Value>) -> Result<()> {
+    let Some(agent) = object.get_mut(AGENT_KEY).and_then(|v| v.as_object_mut()) else {
+        return Ok(());
+    };
+
+    if let Some(tools) = agent
+        .get_mut(TOOL_PERMISSIONS_KEY)
+        .and_then(|v| v.as_object_mut())
+        .and_then(|tp| tp.get_mut(TOOLS_KEY))
+        .and_then(|v| v.as_object_mut())
+    {
+        rename_key(tools);
+    }
+
+    if let Some(profiles) = agent.get_mut(PROFILES_KEY).and_then(|v| v.as_object_mut()) {
+        for (_profile_name, profile) in profiles.iter_mut() {
+            if let Some(tools) = profile
+                .as_object_mut()
+                .and_then(|p| p.get_mut(TOOLS_KEY))
+                .and_then(|v| v.as_object_mut())
+            {
+                rename_key(tools);
+            }
+        }
+    }
+
+    Ok(())
+}
+
+fn rename_key(tools: &mut serde_json::Map<String, Value>) {
+    if let Some(value) = tools.remove(OLD_TOOL_NAME) {
+        tools.insert(NEW_TOOL_NAME.to_string(), value);
+    }
+}

crates/migrator/src/migrator.rs 🔗

@@ -247,6 +247,7 @@ pub fn migrate_settings(text: &str) -> Result<Option<String>> {
             migrations::m_2026_03_16::SETTINGS_PATTERNS,
             &SETTINGS_QUERY_2026_03_16,
         ),
+        MigrationType::Json(migrations::m_2026_04_10::rename_web_search_to_search_web),
     ];
     run_migrations(text, migrations)
 }
@@ -4480,4 +4481,348 @@ mod tests {
             ),
         );
     }
+
+    #[test]
+    fn test_rename_web_search_to_search_web_in_tool_permissions() {
+        assert_migrate_with_migrations(
+            &[MigrationType::Json(
+                migrations::m_2026_04_10::rename_web_search_to_search_web,
+            )],
+            &r#"
+            {
+                "agent": {
+                    "tool_permissions": {
+                        "tools": {
+                            "web_search": {
+                                "allow": true
+                            }
+                        }
+                    }
+                }
+            }
+            "#
+            .unindent(),
+            Some(
+                &r#"
+                {
+                    "agent": {
+                        "tool_permissions": {
+                            "tools": {
+                                "search_web": {
+                                    "allow": true
+                                }
+                            }
+                        }
+                    }
+                }
+                "#
+                .unindent(),
+            ),
+        );
+    }
+
+    #[test]
+    fn test_rename_web_search_to_search_web_in_profiles() {
+        assert_migrate_with_migrations(
+            &[MigrationType::Json(
+                migrations::m_2026_04_10::rename_web_search_to_search_web,
+            )],
+            &r#"
+            {
+                "agent": {
+                    "profiles": {
+                        "write": {
+                            "tools": {
+                                "web_search": false
+                            }
+                        }
+                    }
+                }
+            }
+            "#
+            .unindent(),
+            Some(
+                &r#"
+                {
+                    "agent": {
+                        "profiles": {
+                            "write": {
+                                "tools": {
+                                    "search_web": false
+                                }
+                            }
+                        }
+                    }
+                }
+                "#
+                .unindent(),
+            ),
+        );
+    }
+
+    #[test]
+    fn test_rename_web_search_to_search_web_no_change_when_already_migrated() {
+        assert_migrate_with_migrations(
+            &[MigrationType::Json(
+                migrations::m_2026_04_10::rename_web_search_to_search_web,
+            )],
+            &r#"
+            {
+                "agent": {
+                    "tool_permissions": {
+                        "tools": {
+                            "search_web": {
+                                "allow": true
+                            }
+                        }
+                    }
+                }
+            }
+            "#
+            .unindent(),
+            None,
+        );
+    }
+
+    #[test]
+    fn test_rename_web_search_to_search_web_no_clobber() {
+        assert_migrate_with_migrations(
+            &[MigrationType::Json(
+                migrations::m_2026_04_10::rename_web_search_to_search_web,
+            )],
+            &r#"
+            {
+                "agent": {
+                    "tool_permissions": {
+                        "tools": {
+                            "web_search": {
+                                "allow": false
+                            },
+                            "search_web": {
+                                "allow": true
+                            }
+                        }
+                    }
+                }
+            }
+            "#
+            .unindent(),
+            Some(
+                &r#"
+                {
+                    "agent": {
+                        "tool_permissions": {
+                            "tools": {
+                                "search_web": {
+                                    "allow": false
+                                }
+                            }
+                        }
+                    }
+                }
+                "#
+                .unindent(),
+            ),
+        );
+    }
+
+    #[test]
+    fn test_rename_web_search_to_search_web_platform_override() {
+        assert_migrate_with_migrations(
+            &[MigrationType::Json(
+                migrations::m_2026_04_10::rename_web_search_to_search_web,
+            )],
+            &r#"
+            {
+                "linux": {
+                    "agent": {
+                        "tool_permissions": {
+                            "tools": {
+                                "web_search": {
+                                    "allow": true
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            "#
+            .unindent(),
+            Some(
+                &r#"
+                {
+                    "linux": {
+                        "agent": {
+                            "tool_permissions": {
+                                "tools": {
+                                    "search_web": {
+                                        "allow": true
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+                "#
+                .unindent(),
+            ),
+        );
+    }
+
+    #[test]
+    fn test_rename_web_search_to_search_web_release_channel_override() {
+        assert_migrate_with_migrations(
+            &[MigrationType::Json(
+                migrations::m_2026_04_10::rename_web_search_to_search_web,
+            )],
+            &r#"
+            {
+                "nightly": {
+                    "agent": {
+                        "tool_permissions": {
+                            "tools": {
+                                "web_search": {
+                                    "default": "allow"
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            "#
+            .unindent(),
+            Some(
+                &r#"
+                {
+                    "nightly": {
+                        "agent": {
+                            "tool_permissions": {
+                                "tools": {
+                                    "search_web": {
+                                        "default": "allow"
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+                "#
+                .unindent(),
+            ),
+        );
+    }
+
+    #[test]
+    fn test_rename_web_search_to_search_web_no_agent() {
+        assert_migrate_with_migrations(
+            &[MigrationType::Json(
+                migrations::m_2026_04_10::rename_web_search_to_search_web,
+            )],
+            &r#"
+            {
+                "buffer_font_size": 14
+            }
+            "#
+            .unindent(),
+            None,
+        );
+    }
+
+    #[test]
+    fn test_rename_web_search_to_search_web_root_level_profile_flat() {
+        assert_migrate_with_migrations(
+            &[MigrationType::Json(
+                migrations::m_2026_04_10::rename_web_search_to_search_web,
+            )],
+            &r#"
+            {
+                "profiles": {
+                    "Work": {
+                        "agent": {
+                            "tool_permissions": {
+                                "tools": {
+                                    "web_search": {
+                                        "default": "allow"
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            "#
+            .unindent(),
+            Some(
+                &r#"
+                {
+                    "profiles": {
+                        "Work": {
+                            "agent": {
+                                "tool_permissions": {
+                                    "tools": {
+                                        "search_web": {
+                                            "default": "allow"
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+                "#
+                .unindent(),
+            ),
+        );
+    }
+
+    #[test]
+    fn test_rename_web_search_to_search_web_root_level_profile() {
+        assert_migrate_with_migrations(
+            &[MigrationType::Json(
+                migrations::m_2026_04_10::rename_web_search_to_search_web,
+            )],
+            &r#"
+            {
+                "profiles": {
+                    "Work": {
+                        "settings": {
+                            "agent": {
+                                "tool_permissions": {
+                                    "tools": {
+                                        "web_search": {
+                                            "default": "allow"
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            "#
+            .unindent(),
+            Some(
+                &r#"
+                {
+                    "profiles": {
+                        "Work": {
+                            "settings": {
+                                "agent": {
+                                    "tool_permissions": {
+                                        "tools": {
+                                            "search_web": {
+                                                "default": "allow"
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+                "#
+                .unindent(),
+            ),
+        );
+    }
 }

crates/settings_ui/src/pages/tool_permissions_setup.rs 🔗

@@ -69,7 +69,7 @@ const TOOLS: &[ToolInfo] = &[
         regex_explanation: "Patterns are matched against the URL being fetched.",
     },
     ToolInfo {
-        id: "web_search",
+        id: "search_web",
         name: "Web Search",
         description: "Web search queries",
         regex_explanation: "Patterns are matched against the search query.",
@@ -309,7 +309,7 @@ fn get_tool_render_fn(
         "create_directory" => render_create_directory_tool_config,
         "save_file" => render_save_file_tool_config,
         "fetch" => render_fetch_tool_config,
-        "web_search" => render_web_search_tool_config,
+        "search_web" => render_web_search_tool_config,
         "restore_file_from_disk" => render_restore_file_from_disk_tool_config,
         _ => render_terminal_tool_config, // fallback
     }
@@ -1389,7 +1389,7 @@ tool_config_page_fn!(render_move_path_tool_config, "move_path");
 tool_config_page_fn!(render_create_directory_tool_config, "create_directory");
 tool_config_page_fn!(render_save_file_tool_config, "save_file");
 tool_config_page_fn!(render_fetch_tool_config, "fetch");
-tool_config_page_fn!(render_web_search_tool_config, "web_search");
+tool_config_page_fn!(render_web_search_tool_config, "search_web");
 tool_config_page_fn!(
     render_restore_file_from_disk_tool_config,
     "restore_file_from_disk"

docs/.doc-examples/reference.md 🔗

@@ -68,7 +68,7 @@ Reads the content of a specified file in the project, allowing access to file co
 
 Allows the Agent to work through problems, brainstorm ideas, or plan without executing actions, useful for complex problem-solving.
 
-### `web_search` {#web-search}
+### `search_web` {#search-web}
 
 Searches the web for information, providing results with snippets and links from relevant web pages, useful for accessing real-time information.
 

docs/src/ai/tool-permissions.md 🔗

@@ -54,7 +54,7 @@ The `tool_permissions` setting lets you customize tool permissions by specifying
 | `restore_file_from_disk` | The file paths               |
 | `save_file`              | The file paths               |
 | `fetch`                  | The URL                      |
-| `web_search`             | The search query             |
+| `search_web`             | The search query             |
 
 For MCP tools, use the format `mcp:<server>:<tool_name>`.
 For example, a tool called `create_issue` on a server called `github` would be `mcp:github:create_issue`.

docs/src/ai/tools.md 🔗

@@ -57,7 +57,7 @@ Reads the content of a specified file in the project, allowing access to file co
 
 Allows the Agent to work through problems, brainstorm ideas, or plan without executing actions, useful for complex problem-solving.
 
-### `web_search`
+### `search_web`
 
 Searches the web for information, providing results with snippets and links from relevant web pages, useful for accessing real-time information.
 

tooling/xtask/src/tasks/workflows/run_tests.rs 🔗

@@ -202,7 +202,7 @@ fn orchestrate_impl(rules: &[&PathCondition], target: OrchestrateTarget) -> Name
 
           # If assets/ changed, add crates that depend on those assets
           if echo "$CHANGED_FILES" | grep -qP '^assets/'; then
-            FILE_CHANGED_PKGS=$(printf '%s\n%s\n%s\n%s' "$FILE_CHANGED_PKGS" "settings" "storybook" "assets" | sort -u)
+            FILE_CHANGED_PKGS=$(printf '%s\n%s\n%s' "$FILE_CHANGED_PKGS" "settings" "assets" | sort -u)
           fi
 
           # Combine all changed packages