1use std::sync::Arc;
4
5use agentic_tools_core::ToolRegistry;
6use agentic_tools_core::context::ToolContext;
7use agentic_tools_core::error::ToolError;
8use agentic_tools_core::tool::Tool;
9use futures::future::BoxFuture;
10
11use crate::WebTools;
12use crate::types::WebFetchInput;
13use crate::types::WebFetchOutput;
14use crate::types::WebSearchInput;
15use crate::types::WebSearchOutput;
16
17#[derive(Clone)]
23pub struct WebFetchTool {
24 tools: Arc<WebTools>,
25}
26
27impl WebFetchTool {
28 #[must_use]
30 pub const fn new(tools: Arc<WebTools>) -> Self {
31 Self { tools }
32 }
33}
34
35impl Tool for WebFetchTool {
36 type Input = WebFetchInput;
37 type Output = WebFetchOutput;
38
39 const NAME: &'static str = "web_fetch";
40 const DESCRIPTION: &'static str = "Fetch a URL over HTTP and convert the page to clean Markdown with metadata. Default summarize=false; set summarize=true to generate a short Haiku summary (requires Anthropic credentials).";
41
42 fn call(
43 &self,
44 input: Self::Input,
45 ctx: &ToolContext,
46 ) -> BoxFuture<'static, Result<Self::Output, ToolError>> {
47 let tools = Arc::clone(&self.tools);
48 let ctx = ctx.clone();
49 Box::pin(async move { crate::fetch::web_fetch(&tools, input, &ctx).await })
50 }
51}
52
53#[derive(Clone)]
59pub struct WebSearchTool {
60 tools: Arc<WebTools>,
61}
62
63impl WebSearchTool {
64 #[must_use]
66 pub const fn new(tools: Arc<WebTools>) -> Self {
67 Self { tools }
68 }
69}
70
71impl Tool for WebSearchTool {
72 type Input = WebSearchInput;
73 type Output = WebSearchOutput;
74
75 const NAME: &'static str = "web_search";
76 const DESCRIPTION: &'static str = "Semantic/neural web search (Exa). Use NATURAL LANGUAGE queries (questions/descriptions). Do NOT use keyword-stuffed, Google-style queries. Returns compact, citable result cards with URLs plus a short trimmed context to orient you.";
77
78 fn call(
79 &self,
80 input: Self::Input,
81 ctx: &ToolContext,
82 ) -> BoxFuture<'static, Result<Self::Output, ToolError>> {
83 let tools = Arc::clone(&self.tools);
84 let ctx = ctx.clone();
85 Box::pin(async move { crate::search::web_search(&tools, input, &ctx).await })
86 }
87}
88
89pub fn build_registry(tools: Arc<WebTools>) -> ToolRegistry {
95 ToolRegistry::builder()
96 .register::<WebFetchTool, ()>(WebFetchTool::new(Arc::clone(&tools)))
97 .register::<WebSearchTool, ()>(WebSearchTool::new(tools))
98 .finish()
99}