Add Open Tool (#27499)
I've seen models try to run `open` in Bash. This is a cross-platform version of that. <img width="634" alt="Screenshot 2025-03-26 at 10 27 40 AM" src="https://github.com/user-attachments/assets/b18cb50f-6e2f-4770-b15c-1040916a420a" /> Release Notes: - N/A
This commit is contained in:
parent
7537f0557f
commit
61be869352
6 changed files with 80 additions and 0 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -724,6 +724,7 @@ dependencies = [
|
|||
"itertools 0.14.0",
|
||||
"language",
|
||||
"language_model",
|
||||
"open",
|
||||
"project",
|
||||
"rand 0.8.5",
|
||||
"release_channel",
|
||||
|
|
|
@ -470,6 +470,7 @@ mlua = { version = "0.10", features = ["lua54", "vendored", "async", "send"] }
|
|||
nanoid = "0.4"
|
||||
nbformat = { version = "0.10.0" }
|
||||
nix = "0.29"
|
||||
open = "5.0.0"
|
||||
num-format = "0.4.4"
|
||||
ordered-float = "2.1.1"
|
||||
palette = { version = "0.7.5", default-features = false, features = ["std"] }
|
||||
|
|
|
@ -35,6 +35,7 @@ ui.workspace = true
|
|||
util.workspace = true
|
||||
workspace.workspace = true
|
||||
worktree.workspace = true
|
||||
open = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
collections = { workspace = true, features = ["test-support"] }
|
||||
|
|
|
@ -10,6 +10,7 @@ mod find_replace_file_tool;
|
|||
mod list_directory_tool;
|
||||
mod move_path_tool;
|
||||
mod now_tool;
|
||||
mod open_tool;
|
||||
mod path_search_tool;
|
||||
mod read_file_tool;
|
||||
mod regex_search_tool;
|
||||
|
@ -34,6 +35,7 @@ use crate::fetch_tool::FetchTool;
|
|||
use crate::find_replace_file_tool::FindReplaceFileTool;
|
||||
use crate::list_directory_tool::ListDirectoryTool;
|
||||
use crate::now_tool::NowTool;
|
||||
use crate::open_tool::OpenTool;
|
||||
use crate::path_search_tool::PathSearchTool;
|
||||
use crate::read_file_tool::ReadFileTool;
|
||||
use crate::regex_search_tool::RegexSearchTool;
|
||||
|
@ -55,6 +57,7 @@ pub fn init(http_client: Arc<HttpClientWithUrl>, cx: &mut App) {
|
|||
registry.register_tool(EditFilesTool);
|
||||
registry.register_tool(ListDirectoryTool);
|
||||
registry.register_tool(NowTool);
|
||||
registry.register_tool(OpenTool);
|
||||
registry.register_tool(PathSearchTool);
|
||||
registry.register_tool(ReadFileTool);
|
||||
registry.register_tool(RegexSearchTool);
|
||||
|
|
68
crates/assistant_tools/src/open_tool.rs
Normal file
68
crates/assistant_tools/src/open_tool.rs
Normal file
|
@ -0,0 +1,68 @@
|
|||
use anyhow::{anyhow, Context as _, Result};
|
||||
use assistant_tool::{ActionLog, Tool};
|
||||
use gpui::{App, AppContext, Entity, Task};
|
||||
use language_model::LanguageModelRequestMessage;
|
||||
use project::Project;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::Arc;
|
||||
use ui::IconName;
|
||||
use util::markdown::MarkdownString;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct OpenToolInput {
|
||||
/// The path or URL to open with the default application.
|
||||
path_or_url: String,
|
||||
}
|
||||
|
||||
pub struct OpenTool;
|
||||
|
||||
impl Tool for OpenTool {
|
||||
fn name(&self) -> String {
|
||||
"open".to_string()
|
||||
}
|
||||
|
||||
fn needs_confirmation(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn description(&self) -> String {
|
||||
include_str!("./open_tool/description.md").to_string()
|
||||
}
|
||||
|
||||
fn icon(&self) -> IconName {
|
||||
IconName::ExternalLink
|
||||
}
|
||||
|
||||
fn input_schema(&self) -> serde_json::Value {
|
||||
let schema = schemars::schema_for!(OpenToolInput);
|
||||
serde_json::to_value(&schema).unwrap()
|
||||
}
|
||||
|
||||
fn ui_text(&self, input: &serde_json::Value) -> String {
|
||||
match serde_json::from_value::<OpenToolInput>(input.clone()) {
|
||||
Ok(input) => format!("Open `{}`", MarkdownString::escape(&input.path_or_url)),
|
||||
Err(_) => "Open file or URL".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn run(
|
||||
self: Arc<Self>,
|
||||
input: serde_json::Value,
|
||||
_messages: &[LanguageModelRequestMessage],
|
||||
_project: Entity<Project>,
|
||||
_action_log: Entity<ActionLog>,
|
||||
cx: &mut App,
|
||||
) -> Task<Result<String>> {
|
||||
let input: OpenToolInput = match serde_json::from_value(input) {
|
||||
Ok(input) => input,
|
||||
Err(err) => return Task::ready(Err(anyhow!(err))),
|
||||
};
|
||||
|
||||
cx.background_spawn(async move {
|
||||
open::that(&input.path_or_url).context("Failed to open URL or file path")?;
|
||||
|
||||
Ok(format!("Successfully opened {}", input.path_or_url))
|
||||
})
|
||||
}
|
||||
}
|
6
crates/assistant_tools/src/open_tool/description.md
Normal file
6
crates/assistant_tools/src/open_tool/description.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
This tool opens a file or URL with the default application associated with it on the user's operating system:
|
||||
- On macOS, it's equivalent to the `open` command
|
||||
- On Windows, it's equivalent to `start`
|
||||
- On Linux, it uses something like `xdg-open`, `gio open`, `gnome-open`, `kde-open`, `wslview` as appropriate
|
||||
|
||||
For example, it can open a web browser with a URL, open a PDF file with the default PDF viewer, etc.
|
Loading…
Add table
Add a link
Reference in a new issue