Skip to main content

ares_tools/tools/
provider_web_search.rs

1use crate::registry::Tool;
2use ares_types::Result;
3use async_trait::async_trait;
4use serde_json::{json, Value};
5
6/// Marker tool that opts the LLM adapter into provider-native web search.
7///
8/// This is not daedra. Daedra remains the `web_search` tool (search-tools).
9/// AresLlm strips this name from function tools and attaches genai
10/// `ToolName::WebSearch`.
11pub struct ProviderWebSearch;
12
13#[async_trait]
14impl Tool for ProviderWebSearch {
15    fn name(&self) -> &str {
16        "provider_web_search"
17    }
18
19    fn description(&self) -> &str {
20        "Enable the LLM provider's built-in web search (OpenAI Responses, Anthropic, Gemini, Ollama, Bedrock). This is not daedra. Daedra remains the `web_search` tool. Provider search is executed by the LLM adapter, not this tool."
21    }
22
23    fn parameters_schema(&self) -> Value {
24        json!({
25            "type": "object",
26            "properties": {}
27        })
28    }
29
30    async fn execute(&self, _args: Value) -> Result<Value> {
31        Ok(json!({
32            "status": "attached",
33            "note": "provider web search is executed by the LLM adapter, not this tool"
34        }))
35    }
36}
37
38#[cfg(test)]
39mod tests {
40    use super::*;
41    use serde_json::json;
42
43    #[test]
44    fn name_is_provider_web_search() {
45        assert_eq!(ProviderWebSearch.name(), "provider_web_search");
46    }
47
48    #[test]
49    fn description_names_providers_and_daedra_split() {
50        let description = ProviderWebSearch.description();
51        assert!(description.contains("OpenAI Responses"));
52        assert!(description.contains("Anthropic"));
53        assert!(description.contains("Gemini"));
54        assert!(description.contains("Ollama"));
55        assert!(description.contains("Bedrock"));
56        assert!(description.contains("not daedra"));
57        assert!(description.contains("`web_search`"));
58    }
59
60    #[test]
61    fn parameters_schema_is_empty_object() {
62        let schema = ProviderWebSearch.parameters_schema();
63        assert_eq!(schema["type"], "object");
64        assert_eq!(schema["properties"], json!({}));
65    }
66
67    #[tokio::test]
68    async fn execute_returns_attached_without_error() {
69        let out = ProviderWebSearch.execute(json!({})).await.unwrap();
70        assert_eq!(out["status"], "attached");
71        assert_eq!(
72            out["note"],
73            "provider web search is executed by the LLM adapter, not this tool"
74        );
75    }
76
77    #[tokio::test]
78    async fn mistaken_function_call_with_args_does_not_fail() {
79        let out = ProviderWebSearch
80            .execute(json!({"query": "should be ignored"}))
81            .await
82            .unwrap();
83        assert_eq!(out["status"], "attached");
84    }
85}