everruns_integrations_duckduckgo/
lib.rs1pub mod client;
26mod tools;
27
28use everruns_core::capabilities::{
29 Capability, CapabilityLocalization, CapabilityStatus, IntegrationPlugin,
30};
31use everruns_core::tools::Tool;
32
33use tools::DuckDuckGoSearchTool;
34
35inventory::submit! {
40 IntegrationPlugin {
41 experimental_only: true,
42 feature_flag: None,
43 factory: || Box::new(DuckDuckGoCapability),
44 }
45}
46
47const DUCKDUCKGO_API_BASE: &str = "https://api.duckduckgo.com";
52
53pub struct DuckDuckGoCapability;
58
59impl Capability for DuckDuckGoCapability {
60 fn id(&self) -> &str {
61 "duckduckgo"
62 }
63
64 fn name(&self) -> &str {
65 "[Experimental] DuckDuckGo"
66 }
67
68 fn description(&self) -> &str {
69 "Look up instant answers using the DuckDuckGo Instant Answer API. \
70 Agents can get abstracts, definitions, related topics, and direct answers. \
71 This is an instant-answer lookup, not a full web/SERP search — no result does \
72 not mean no web pages exist. \
73 EXPERIMENTAL: This capability may change."
74 }
75
76 fn status(&self) -> CapabilityStatus {
77 CapabilityStatus::Available
78 }
79
80 fn icon(&self) -> Option<&str> {
81 Some("search")
82 }
83
84 fn category(&self) -> Option<&str> {
85 Some("Network")
86 }
87
88 fn system_prompt_addition(&self) -> Option<&str> {
89 Some(
94 "`duckduckgo_instant_answer` returns curated instant answers (facts, definitions, abstracts), not general web results. An empty result does not mean no matching web pages exist; prefer a web-search or web-fetch tool for web discovery, but this tool can serve as a lightweight fallback when none is available.",
95 )
96 }
97
98 fn tools(&self) -> Vec<Box<dyn Tool>> {
99 vec![Box::new(DuckDuckGoSearchTool)]
100 }
101
102 fn dependencies(&self) -> Vec<&'static str> {
103 vec![]
104 }
105
106 fn localizations(&self) -> Vec<CapabilityLocalization> {
107 vec![CapabilityLocalization::text(
108 "uk",
109 "[Експериментально] DuckDuckGo",
110 "Шукайте миттєві відповіді через DuckDuckGo Instant Answer API. Агенти можуть \
111 отримувати анотації, визначення, пов'язані теми та прямі відповіді. \
112 Це пошук миттєвих відповідей, а не повноцінний веб-пошук — відсутність \
113 результату не означає, що немає відповідних веб-сторінок. \
114 ЕКСПЕРИМЕНТАЛЬНО: ця можливість може змінитися.",
115 )]
116 }
117}
118
119#[cfg(test)]
124mod tests {
125 use super::*;
126 use everruns_core::capabilities::CapabilityStatus;
127
128 #[test]
129 fn test_capability_metadata() {
130 let cap = DuckDuckGoCapability;
131 assert_eq!(cap.id(), "duckduckgo");
132 assert_eq!(cap.name(), "[Experimental] DuckDuckGo");
133 assert_eq!(cap.status(), CapabilityStatus::Available);
134 assert_eq!(cap.icon(), Some("search"));
135 assert_eq!(cap.category(), Some("Network"));
136 }
137
138 #[test]
139 fn test_capability_has_all_tools() {
140 let cap = DuckDuckGoCapability;
141 let tools = cap.tools();
142 assert_eq!(tools.len(), 1);
143
144 let names: Vec<&str> = tools.iter().map(|t| t.name()).collect();
145 assert!(names.contains(&"duckduckgo_instant_answer"));
146 }
147
148 #[test]
149 fn test_capability_has_system_prompt() {
150 let cap = DuckDuckGoCapability;
151 let prompt = cap.system_prompt_addition().unwrap();
152 assert!(prompt.contains("duckduckgo_instant_answer"));
156 assert!(prompt.contains("instant answers"));
157 }
158
159 #[test]
160 fn test_capability_no_dependencies() {
161 let cap = DuckDuckGoCapability;
162 assert!(cap.dependencies().is_empty());
163 }
164}