agent2: Add now, grep, and web search tools (#35974)
Release Notes: - N/A --------- Co-authored-by: Bennet Bo Fenner <bennetbo@gmx.de> Co-authored-by: Antonio Scandurra <me@as-cii.com>
This commit is contained in:
parent
ebcce8730d
commit
8dbded46d8
8 changed files with 1390 additions and 4 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -191,6 +191,7 @@ dependencies = [
|
|||
"anyhow",
|
||||
"assistant_tool",
|
||||
"assistant_tools",
|
||||
"chrono",
|
||||
"client",
|
||||
"clock",
|
||||
"cloud_llm_client",
|
||||
|
@ -227,10 +228,13 @@ dependencies = [
|
|||
"tempfile",
|
||||
"terminal",
|
||||
"theme",
|
||||
"tree-sitter-rust",
|
||||
"ui",
|
||||
"unindent",
|
||||
"util",
|
||||
"uuid",
|
||||
"watch",
|
||||
"web_search",
|
||||
"which 6.0.3",
|
||||
"workspace-hack",
|
||||
"worktree",
|
||||
|
|
|
@ -20,6 +20,7 @@ agent_settings.workspace = true
|
|||
anyhow.workspace = true
|
||||
assistant_tool.workspace = true
|
||||
assistant_tools.workspace = true
|
||||
chrono.workspace = true
|
||||
cloud_llm_client.workspace = true
|
||||
collections.workspace = true
|
||||
fs.workspace = true
|
||||
|
@ -49,6 +50,7 @@ ui.workspace = true
|
|||
util.workspace = true
|
||||
uuid.workspace = true
|
||||
watch.workspace = true
|
||||
web_search.workspace = true
|
||||
which.workspace = true
|
||||
workspace-hack.workspace = true
|
||||
|
||||
|
@ -71,5 +73,7 @@ settings = { workspace = true, "features" = ["test-support"] }
|
|||
tempfile.workspace = true
|
||||
terminal = { workspace = true, "features" = ["test-support"] }
|
||||
theme = { workspace = true, "features" = ["test-support"] }
|
||||
tree-sitter-rust.workspace = true
|
||||
unindent = { workspace = true }
|
||||
worktree = { workspace = true, "features" = ["test-support"] }
|
||||
zlog.workspace = true
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use crate::{AgentResponseEvent, Thread, templates::Templates};
|
||||
use crate::{
|
||||
CopyPathTool, CreateDirectoryTool, EditFileTool, FindPathTool, ListDirectoryTool, MovePathTool,
|
||||
OpenTool, ReadFileTool, TerminalTool, ThinkingTool, ToolCallAuthorization,
|
||||
CopyPathTool, CreateDirectoryTool, EditFileTool, FindPathTool, GrepTool, ListDirectoryTool,
|
||||
MovePathTool, NowTool, OpenTool, ReadFileTool, TerminalTool, ThinkingTool,
|
||||
ToolCallAuthorization, WebSearchTool,
|
||||
};
|
||||
use acp_thread::ModelSelector;
|
||||
use agent_client_protocol as acp;
|
||||
|
@ -424,9 +425,13 @@ impl acp_thread::AgentConnection for NativeAgentConnection {
|
|||
thread.add_tool(OpenTool::new(project.clone()));
|
||||
thread.add_tool(ThinkingTool);
|
||||
thread.add_tool(FindPathTool::new(project.clone()));
|
||||
thread.add_tool(GrepTool::new(project.clone()));
|
||||
thread.add_tool(ReadFileTool::new(project.clone(), action_log));
|
||||
thread.add_tool(EditFileTool::new(cx.entity()));
|
||||
thread.add_tool(NowTool);
|
||||
thread.add_tool(TerminalTool::new(project.clone(), cx));
|
||||
// TODO: Needs to be conditional based on zed model or not
|
||||
thread.add_tool(WebSearchTool);
|
||||
thread
|
||||
});
|
||||
|
||||
|
|
|
@ -3,21 +3,27 @@ mod create_directory_tool;
|
|||
mod delete_path_tool;
|
||||
mod edit_file_tool;
|
||||
mod find_path_tool;
|
||||
mod grep_tool;
|
||||
mod list_directory_tool;
|
||||
mod move_path_tool;
|
||||
mod now_tool;
|
||||
mod open_tool;
|
||||
mod read_file_tool;
|
||||
mod terminal_tool;
|
||||
mod thinking_tool;
|
||||
mod web_search_tool;
|
||||
|
||||
pub use copy_path_tool::*;
|
||||
pub use create_directory_tool::*;
|
||||
pub use delete_path_tool::*;
|
||||
pub use edit_file_tool::*;
|
||||
pub use find_path_tool::*;
|
||||
pub use grep_tool::*;
|
||||
pub use list_directory_tool::*;
|
||||
pub use move_path_tool::*;
|
||||
pub use now_tool::*;
|
||||
pub use open_tool::*;
|
||||
pub use read_file_tool::*;
|
||||
pub use terminal_tool::*;
|
||||
pub use thinking_tool::*;
|
||||
pub use web_search_tool::*;
|
||||
|
|
1196
crates/agent2/src/tools/grep_tool.rs
Normal file
1196
crates/agent2/src/tools/grep_tool.rs
Normal file
File diff suppressed because it is too large
Load diff
66
crates/agent2/src/tools/now_tool.rs
Normal file
66
crates/agent2/src/tools/now_tool.rs
Normal file
|
@ -0,0 +1,66 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use agent_client_protocol as acp;
|
||||
use anyhow::Result;
|
||||
use chrono::{Local, Utc};
|
||||
use gpui::{App, SharedString, Task};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{AgentTool, ToolCallEventStream};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum Timezone {
|
||||
/// Use UTC for the datetime.
|
||||
Utc,
|
||||
/// Use local time for the datetime.
|
||||
Local,
|
||||
}
|
||||
|
||||
/// Returns the current datetime in RFC 3339 format.
|
||||
/// Only use this tool when the user specifically asks for it or the current task would benefit from knowing the current datetime.
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct NowToolInput {
|
||||
/// The timezone to use for the datetime.
|
||||
timezone: Timezone,
|
||||
}
|
||||
|
||||
pub struct NowTool;
|
||||
|
||||
impl AgentTool for NowTool {
|
||||
type Input = NowToolInput;
|
||||
type Output = String;
|
||||
|
||||
fn name(&self) -> SharedString {
|
||||
"now".into()
|
||||
}
|
||||
|
||||
fn kind(&self) -> acp::ToolKind {
|
||||
acp::ToolKind::Other
|
||||
}
|
||||
|
||||
fn initial_title(&self, _input: Result<Self::Input, serde_json::Value>) -> SharedString {
|
||||
"Get current time".into()
|
||||
}
|
||||
|
||||
fn run(
|
||||
self: Arc<Self>,
|
||||
input: Self::Input,
|
||||
event_stream: ToolCallEventStream,
|
||||
_cx: &mut App,
|
||||
) -> Task<Result<String>> {
|
||||
let now = match input.timezone {
|
||||
Timezone::Utc => Utc::now().to_rfc3339(),
|
||||
Timezone::Local => Local::now().to_rfc3339(),
|
||||
};
|
||||
let content = format!("The current datetime is {now}.");
|
||||
|
||||
event_stream.update_fields(acp::ToolCallUpdateFields {
|
||||
content: Some(vec![content.clone().into()]),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
Task::ready(Ok(content))
|
||||
}
|
||||
}
|
105
crates/agent2/src/tools/web_search_tool.rs
Normal file
105
crates/agent2/src/tools/web_search_tool.rs
Normal file
|
@ -0,0 +1,105 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use crate::{AgentTool, ToolCallEventStream};
|
||||
use agent_client_protocol as acp;
|
||||
use anyhow::{Result, anyhow};
|
||||
use cloud_llm_client::WebSearchResponse;
|
||||
use gpui::{App, AppContext, Task};
|
||||
use language_model::LanguageModelToolResultContent;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ui::prelude::*;
|
||||
use web_search::WebSearchRegistry;
|
||||
|
||||
/// Search the web for information using your query.
|
||||
/// Use this when you need real-time information, facts, or data that might not be in your training. \
|
||||
/// Results will include snippets and links from relevant web pages.
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct WebSearchToolInput {
|
||||
/// The search term or question to query on the web.
|
||||
query: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct WebSearchToolOutput(WebSearchResponse);
|
||||
|
||||
impl From<WebSearchToolOutput> for LanguageModelToolResultContent {
|
||||
fn from(value: WebSearchToolOutput) -> Self {
|
||||
serde_json::to_string(&value.0)
|
||||
.expect("Failed to serialize WebSearchResponse")
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WebSearchTool;
|
||||
|
||||
impl AgentTool for WebSearchTool {
|
||||
type Input = WebSearchToolInput;
|
||||
type Output = WebSearchToolOutput;
|
||||
|
||||
fn name(&self) -> SharedString {
|
||||
"web_search".into()
|
||||
}
|
||||
|
||||
fn kind(&self) -> acp::ToolKind {
|
||||
acp::ToolKind::Fetch
|
||||
}
|
||||
|
||||
fn initial_title(&self, _input: Result<Self::Input, serde_json::Value>) -> SharedString {
|
||||
"Searching the Web".into()
|
||||
}
|
||||
|
||||
fn run(
|
||||
self: Arc<Self>,
|
||||
input: Self::Input,
|
||||
event_stream: ToolCallEventStream,
|
||||
cx: &mut App,
|
||||
) -> Task<Result<Self::Output>> {
|
||||
let Some(provider) = WebSearchRegistry::read_global(cx).active_provider() else {
|
||||
return Task::ready(Err(anyhow!("Web search is not available.")));
|
||||
};
|
||||
|
||||
let search_task = provider.search(input.query, cx);
|
||||
cx.background_spawn(async move {
|
||||
let response = match search_task.await {
|
||||
Ok(response) => response,
|
||||
Err(err) => {
|
||||
event_stream.update_fields(acp::ToolCallUpdateFields {
|
||||
title: Some("Web Search Failed".to_string()),
|
||||
..Default::default()
|
||||
});
|
||||
return Err(err);
|
||||
}
|
||||
};
|
||||
|
||||
let result_text = if response.results.len() == 1 {
|
||||
"1 result".to_string()
|
||||
} else {
|
||||
format!("{} results", response.results.len())
|
||||
};
|
||||
event_stream.update_fields(acp::ToolCallUpdateFields {
|
||||
title: Some(format!("Searched the web: {result_text}")),
|
||||
content: Some(
|
||||
response
|
||||
.results
|
||||
.iter()
|
||||
.map(|result| acp::ToolCallContent::Content {
|
||||
content: acp::ContentBlock::ResourceLink(acp::ResourceLink {
|
||||
name: result.title.clone(),
|
||||
uri: result.url.clone(),
|
||||
title: Some(result.title.clone()),
|
||||
description: Some(result.text.clone()),
|
||||
mime_type: None,
|
||||
annotations: None,
|
||||
size: None,
|
||||
}),
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
..Default::default()
|
||||
});
|
||||
Ok(WebSearchToolOutput(response))
|
||||
})
|
||||
}
|
||||
}
|
|
@ -263,12 +263,12 @@ pub struct WebSearchBody {
|
|||
pub query: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct WebSearchResponse {
|
||||
pub results: Vec<WebSearchResult>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct WebSearchResult {
|
||||
pub title: String,
|
||||
pub url: String,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue