zeroclaw_tools/
web_search_provider_routing.rs1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2pub enum WebSearchProviderRoute {
3 DuckDuckGo,
4 Brave,
5 SearXNG,
6 Tavily,
7 Jina,
8}
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub struct WebSearchProviderResolution {
12 pub route: WebSearchProviderRoute,
13 pub canonical_provider: &'static str,
14 pub used_fallback: bool,
15}
16
17pub const DEFAULT_WEB_SEARCH_PROVIDER: &str = "duckduckgo";
18const BRAVE_PROVIDER: &str = "brave";
19const SEARXNG_PROVIDER: &str = "searxng";
20const TAVILY_PROVIDER: &str = "tavily";
21const JINA_PROVIDER: &str = "jina";
22
23pub fn resolve_web_search_provider(raw_model_provider: &str) -> WebSearchProviderResolution {
24 let normalized = raw_model_provider.trim().to_ascii_lowercase();
25 match normalized.as_str() {
26 "" | "default" | "duckduckgo" | "ddg" | "duck-duck-go" | "duck_duck_go" => {
27 WebSearchProviderResolution {
28 route: WebSearchProviderRoute::DuckDuckGo,
29 canonical_provider: DEFAULT_WEB_SEARCH_PROVIDER,
30 used_fallback: false,
31 }
32 }
33 "brave" | "brave-search" | "brave_search" => WebSearchProviderResolution {
34 route: WebSearchProviderRoute::Brave,
35 canonical_provider: BRAVE_PROVIDER,
36 used_fallback: false,
37 },
38 "searxng" | "searx" | "searx-ng" | "searx_ng" => WebSearchProviderResolution {
39 route: WebSearchProviderRoute::SearXNG,
40 canonical_provider: SEARXNG_PROVIDER,
41 used_fallback: false,
42 },
43 "tavily" | "tavily-search" | "tavily_search" => WebSearchProviderResolution {
44 route: WebSearchProviderRoute::Tavily,
45 canonical_provider: TAVILY_PROVIDER,
46 used_fallback: false,
47 },
48 "jina" | "jina-ai" | "jina_ai" => WebSearchProviderResolution {
49 route: WebSearchProviderRoute::Jina,
50 canonical_provider: JINA_PROVIDER,
51 used_fallback: false,
52 },
53 _ => WebSearchProviderResolution {
56 route: WebSearchProviderRoute::DuckDuckGo,
57 canonical_provider: DEFAULT_WEB_SEARCH_PROVIDER,
58 used_fallback: true,
59 },
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66
67 #[test]
68 fn resolve_aliases_to_duckduckgo() {
69 let ddg_aliases = ["duckduckgo", "ddg", "duck-duck-go", "duck_duck_go"];
70 for alias in ddg_aliases {
71 let resolved = resolve_web_search_provider(alias);
72 assert_eq!(resolved.route, WebSearchProviderRoute::DuckDuckGo);
73 assert_eq!(resolved.canonical_provider, DEFAULT_WEB_SEARCH_PROVIDER);
74 assert!(!resolved.used_fallback);
75 }
76 }
77
78 #[test]
79 fn resolve_aliases_to_brave() {
80 let brave_aliases = ["brave", "brave-search", "brave_search"];
81 for alias in brave_aliases {
82 let resolved = resolve_web_search_provider(alias);
83 assert_eq!(resolved.route, WebSearchProviderRoute::Brave);
84 assert_eq!(resolved.canonical_provider, BRAVE_PROVIDER);
85 assert!(!resolved.used_fallback);
86 }
87 }
88
89 #[test]
90 fn resolve_aliases_to_searxng() {
91 let searxng_aliases = ["searxng", "searx", "searx-ng", "searx_ng"];
92 for alias in searxng_aliases {
93 let resolved = resolve_web_search_provider(alias);
94 assert_eq!(resolved.route, WebSearchProviderRoute::SearXNG);
95 assert_eq!(resolved.canonical_provider, SEARXNG_PROVIDER);
96 assert!(!resolved.used_fallback);
97 }
98 }
99
100 #[test]
101 fn resolve_aliases_to_tavily() {
102 let tavily_aliases = ["tavily", "tavily-search", "tavily_search"];
103 for alias in tavily_aliases {
104 let resolved = resolve_web_search_provider(alias);
105 assert_eq!(resolved.route, WebSearchProviderRoute::Tavily);
106 assert_eq!(resolved.canonical_provider, TAVILY_PROVIDER);
107 assert!(!resolved.used_fallback);
108 }
109 }
110
111 #[test]
112 fn resolve_aliases_to_jina() {
113 let jina_aliases = ["jina", "jina-ai", "jina_ai"];
114 for alias in jina_aliases {
115 let resolved = resolve_web_search_provider(alias);
116 assert_eq!(resolved.route, WebSearchProviderRoute::Jina);
117 assert_eq!(resolved.canonical_provider, JINA_PROVIDER);
118 assert!(!resolved.used_fallback);
119 }
120 }
121
122 #[test]
123 fn resolve_unknown_provider_falls_back_to_default() {
124 let resolved = resolve_web_search_provider("bing");
125 assert_eq!(resolved.route, WebSearchProviderRoute::DuckDuckGo);
126 assert_eq!(resolved.canonical_provider, DEFAULT_WEB_SEARCH_PROVIDER);
127 assert!(resolved.used_fallback);
128
129 let resolved2 = resolve_web_search_provider("searxng-plus");
130 assert_eq!(resolved2.route, WebSearchProviderRoute::DuckDuckGo);
131 assert_eq!(resolved2.canonical_provider, DEFAULT_WEB_SEARCH_PROVIDER);
132 assert!(resolved2.used_fallback);
133 }
134}